news 2026/5/7 16:58:26

模板编程——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/5/3 11:16:51

开题报告 springboot和vue-信贷管理信息系统

目录 系统背景与需求技术选型分析核心功能模块系统优势应用场景 项目技术支持可定制开发之功能亮点源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作 系统背景与需求 信贷管理信息系统旨在解决传统信贷业务中流程繁琐、数据分散、效率低下等…

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

24.Android系统源码-libpng 实战 - PNG无损压缩核心技术

libpng 实战 - PNG无损压缩核心技术 源码: external/libpng/ (~35,000行 C) 标准: PNG 1.2规范 (ISO/IEC 15948) 用途: Android图标/UI资源/截图的PNG处理引擎 依赖: zlib (DEFLATE压缩核心) 1. 为什么PNG而非JPEG? 关键差异: PNG (Portable Network Graphics):压缩: 无损 (…

作者头像 李华
网站建设 2026/5/2 21:42:05

导师严选9个降AIGC平台 千笔AI帮你精准降AI率

AI降重工具&#xff0c;让论文更自然、更安全 随着人工智能技术的广泛应用&#xff0c;越来越多的高校和导师开始重视论文中的AIGC率问题。对于本科生而言&#xff0c;一篇论文不仅要内容严谨、逻辑清晰&#xff0c;还要避免被系统判定为AI生成内容。这就需要借助专业的AI降重工…

作者头像 李华
网站建设 2026/5/5 17:32:22

2026-02-04 校⻓公开直播

一、开年解读 还有一点原因是最近发现有些股票确实挺好 一直强调淡化指数,关注板块; 三月之前由于特朗普会有来华预期,所以在访华之前中美博弈相关风险影响不会很大;

作者头像 李华
网站建设 2026/5/2 15:47:24

FX5U与JE-C伺服通讯:从入门到实战

FX5U和je-C伺服通讯案例和学习资料&#xff0c;绝无仅有。物超所值 最近在工作中接触到了三菱FX5U PLC与JE-C伺服电机的通讯配置&#xff0c;感觉这个过程既有趣又有挑战性。作为一个刚入行的工程师&#xff0c;一开始面对伺服系统时&#xff0c;确实有点摸不着头脑&#xff0…

作者头像 李华
网站建设 2026/5/3 3:29:07

阿里开源Qwen3-Coder-Next,80B参数仅激活3B的MoE顶尖编程助手

阿里刚刚开源了极强的小型 MoE 代码模型 Qwen3-Coder-Next。Qwen3-Coder-Next 以 800 亿总参数量和仅 30 亿的激活参数量&#xff0c;在代码生成与智能体任务中展示了极高的效能与潜力。尽管激活参数规模很小&#xff0c;在 SWE-Bench&#xff08;Verified、Multilingual、Pro&…

作者头像 李华