news 2026/5/9 18:38:00

模板编程——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/4/18 3:40:45

导师推荐!千笔,顶尖配置的AI论文写作软件

你是否曾为论文选题而苦恼&#xff1f;是否在深夜面对空白文档时感到无从下手&#xff1f;是否反复修改却总对表达不满意&#xff1f;论文写作不仅是学术能力的考验&#xff0c;更是时间与精力的挑战。对于本科生来说&#xff0c;从选题到查重&#xff0c;每一步都可能成为“卡…

作者头像 李华
网站建设 2026/5/6 2:38:52

Jenkins节点拉取代码报错场景及解决方案全解析

Jenkins节点在拉取代码时可能因多种原因报错&#xff0c;涵盖SSH认证、网络配置、Git环境、权限管理等问题。本文从问题机制和解决方案两个维度&#xff0c;系统梳理常见场景及处理方法&#xff0c;帮助快速定位和修复问题。一、SSH认证相关问题 1. 密钥算法不匹配 现象&#x…

作者头像 李华
网站建设 2026/5/1 8:37:27

全网最全8个降AIGC网站,千笔AI助你高效降AI率

AI降重工具&#xff1a;高效降低AIGC率&#xff0c;守护学术诚信 在当前学术研究日益依赖AI辅助写作的背景下&#xff0c;如何有效降低论文中的AIGC率&#xff0c;已成为研究生们关注的核心问题。随着各大高校和期刊对AI生成内容的识别技术不断升级&#xff0c;单纯依靠AI撰写…

作者头像 李华
网站建设 2026/5/1 6:26:31

多平台环境下大文件上传的通用解决方案总结?

2023年XX月XX日 &#x1f31f; | 一个菜鸟程序员的“秃头”日记 &#x1f4bb; 今日份的崩溃与突破 早上8点&#xff1a;对着镜子默念三遍——“我能搞定10G文件上传&#xff01;”&#xff08;然后发现IE8连console.log都报错…&#xff09; 上午10点&#xff1a;试图用WebU…

作者头像 李华
网站建设 2026/4/23 15:17:20

智能制造MES系统如何实现SPC控制图到富文本编辑器的动态绑定?

重庆XX教育集团项目评估与技术方案 ——基于信创环境的富文本编辑器增强模块开发纪实 一、需求分析与技术评估 1. 核心需求矩阵 需求分类具体要求技术挑战点内容粘贴Word/微信公众号图文粘贴&#xff08;含图片自动上传&#xff09;IE8下Clipboard API兼容性、微信公众号反爬…

作者头像 李华