news 2026/7/15 6:31:07

模板编程——std::is_pointer的分析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
模板编程——std::is_pointer的分析

一、模板元编程库

在C++的标准库中提供了相关的元编程库,提供了一系列的对相关元编程相关的接口,极大的方便了开发者在元编程时的工作。在前面也分析过几个元编程的接口,今天接着分析一下指针处理的元编程接口std::is_pointer。

二、std::is_pointer

标准库中对其的定义为:

template<class T>structis_pointer;

说明也写得非常清楚,它只能检查T是不是一个对象或函数的指针,还特别注明了包括void指针但不包括成员指针。它提供了对cv限定符的支持,其可能实现的源码如下:

template<class T>structis_pointer:std::false_type{};template<class T>structis_pointer<T*>:std::true_type{};template<class T>structis_pointer<T*const>:std::true_type{};template<class T>structis_pointer<T*volatile>:std::true_type{};template<class T>structis_pointer<T*constvolatile>:std::true_type{};

std::true_type这哥俩用到的地方还是挺频繁的。这段代码没啥可解析的,在不同的库中,实现有些大同小异,但基本都差不多。再看一个cppreference的例子:

#include<type_traits>intmain(){structA{intm;voidf(){}};intA::*mem_data_ptr=&A::m;// a pointer to member datavoid(A::*mem_fun_ptr)()=&A::f;// a pointer to member functionstatic_assert(!std::is_pointer<A>::value&&!std::is_pointer_v<A>// same thing as above, but in C++17!&&!std::is_pointer<A>()// same as above, using inherited operator bool&&!std::is_pointer<A>{}// ditto&&!std::is_pointer<A>()()// same as above, using inherited operator()&&!std::is_pointer<A>{}()// ditto&&std::is_pointer_v<A*>&&std::is_pointer_v<Aconst*volatile>&&!std::is_pointer_v<A&>&&!std::is_pointer_v<decltype(mem_data_ptr)>&&!std::is_pointer_v<decltype(mem_fun_ptr)>&&std::is_pointer_v<void*>&&!std::is_pointer_v<int>&&std::is_pointer_v<int*>&&std::is_pointer_v<int**>&&!std::is_pointer_v<int[10]>&&!std::is_pointer_v<std::nullptr_t>&&std::is_pointer_v<void(*)()>);}

是不是觉得代码很easy,确实如此。但越是这样越是要小心。

三、问题和分析

将上面的代码改一下,直接传递进去一个多级指针会是什么样呢?比如下面这样:

class Demo{};intmain(){static_assert(std::is_pointer<Demo*>::value,"Demo is not a pointer type");static_assert(std::is_pointer<Demo**>::value,"Demo is not a pointer type");return0;}

这种情况顺利的通过了编译。表面上看上去没问题,如果只是单纯的处理指针可能觉得也没有什么问题啊。但实际上,如果实际的目的操作的是一个“*Demo”时,前者可以得到一个Demo的对象而后者只能得到一个Demo的指针,这就让后面的行为出现了异化。这对于普通编程来说还好发现,但对于模板编程时,可能就很难定位问题。这就需要进行预防性的处理。
有的开发者可能还没有细看说明,把成员内的指针提供给了这个接口应用,如下面这样:

structS{intfoo(){return0;}};intmain(){static_assert(std::is_pointer<decltype(&S::foo)>::value,"S::foo is not a member pointer");//static_assert(std::is_member_pointer<decltype(&S::foo)>::value, "S::foo is not a member pointer");//OKreturn0;}

这也是不正确的用法。说明中详细了表示了不支持成员指针的处理。所以在元编程的标准库中还提供了一个std::is_member_pointer,用来判断成员的指针属性的情况,也算是完善了std::is_pointer不能判断成员指针的情况。

四、处理方法

那么如何处理is_pointer只能检测最外层指针的情况呢?最简单的方法仍然是采用元编程库提供的std::remove_pointer递归判断。毕竟,几乎没有人写超过三级指针的情况,到二级已经是大多数人的极限了。用大牛的话说,不是说不可以用更多级的指针实现,但这恰恰说明了设计上的问题。扯远了,先看使用std::remove_pointer递归解决二级指针的处理方式:

#include<iostream>#include<type_traits>template<typename T>voidcheckPointerLevel(T ptr){ifconstexpr(std::is_pointer_v<T>){std::cout<<"this is pointer!";// 递归检查指针级别intlevel=0;using curType=T;// remove_pointer处理并检查using BaseType=std::remove_pointer_t<T>;ifconstexpr(std::is_pointer_v<BaseType>){std::cout<<"twice-level pointer!"<<std::endl;}else{std::cout<<"first-level pointer!"<<std::endl;}}else{std::cout<<"not a pointer!"<<std::endl;}}

当然也可以使用SFINAE技术处理:

#include<iostream>#include<type_traits>#include<vector>template<typename T>voidimplCheck(T value,std::true_type){using BaseType=typename std::remove_pointer<T>::type;//业务处理}template<typename T>voidimplCheck(T value,std::false_type){//业务处理}template<class U>voidprocess(U&&t){implCheck(std::forward<U>(t),std::is_pointer<std::remove_reference_t<U>>{});}

其实原理都在前面分析过,此处不再赘述。代码也不复杂,明白几个基础的元编程接口即可。

五、总结

在应用库或者第三方接口时,要认真严格的查看相关的接口说明,一定不能想当然的进行利用。本文这个指针处理的元编程接口,就很容易让初学者上当。这就需要开发者能够全面细致的掌握应用的细节并在适当的例程中进行测试验证。这样才能更好的在工程实践中写出健壮稳定的代码。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/10 6:43:57

计算机网络经典问题透视:蜂窝网络切换如何“扼杀”你的TCP连接?

摘要&#xff1a;在2026年的今天&#xff0c;5G网络已然普及&#xff0c;我们享受着前所未有的移动互联体验。然而&#xff0c;一个自移动通信诞生之初就存在的经典问题依然在幕后影响着我们的每一次连接&#xff1a;当您乘坐高铁、在城市中移动时&#xff0c;手机在不同基站间…

作者头像 李华
网站建设 2026/7/9 6:32:19

真心不骗你!继续教育论文神器 —— 千笔ai写作

你是否还在为论文选题发愁&#xff1f;是否在写作过程中感到无从下手&#xff1f;又或者&#xff0c;反复修改却依然不满意&#xff1f;论文写作的每一个环节都可能成为压力源&#xff0c;尤其是对于继续教育的学生来说&#xff0c;时间紧张、精力有限&#xff0c;更需要一个高…

作者头像 李华
网站建设 2026/7/6 17:55:33

http协议下如何实现大文件切片上传的解决方案总结?

首先右键单击网站根目录,在弹出的快捷菜单中,选择"添加引用"菜单项,弹出"添加引用",切换到"浏览"找到组件的Dll文件"Bestcomy.Web.Controls.Upload.dll"(本文件可到官网下载,本文后面也提供下载),单击"确定",回到VS工作界面…

作者头像 李华
网站建设 2026/7/8 6:52:18

2025丙烷传感器选型指南与传感器应用方案解析

丙烷&#xff08;C₃H₈&#xff09;是一种易燃气体&#xff0c;广泛应用于工业燃料、家庭供暖、烹饪、化工生产等领域&#xff0c;但其潜在的泄漏风险对环境和安全构成威胁。丙烷传感器作为检测丙烷浓度的关键设备&#xff0c;在气体检测、工业安全、智能家居和环境监测等行业…

作者头像 李华
网站建设 2026/7/14 0:28:09

改稿速度拉满!继续教育论文神器 —— 千笔写作工具

你是否曾为论文选题发愁&#xff0c;反复修改却总对表达不满意&#xff1f;是否在查重率和格式问题上焦头烂额&#xff1f;继续教育的同学们&#xff0c;论文写作不仅是学术能力的考验&#xff0c;更是时间与精力的挑战。面对海量文献、复杂结构和严格规范&#xff0c;很多人陷…

作者头像 李华