首页 > 编程语言 >C++ 【元编程】检查类型是否具有成员 hasattr

C++ 【元编程】检查类型是否具有成员 hasattr

时间:2024-07-29 17:55:31浏览次数:14  
标签:void 编程 C++ func printf test my class hasattr

在python中,可以使用hasattr判断类型是否具有某个成员。

在C++中,有的时候我们要写一个模板函数,需要对模板进行一定的限制时。这些限制可能为“该模板函数仅用于拥有某个成员的类型”。在标准<type_traits>中,规定了一些列如is_copy_assignable等模板常量,用于判断是否拥有拷贝构造函数等成员,但对于其他自定义的成员,我们要如何判断呢?

在C++中有两种方式可以检查类型是否具有某个成员:

1、虚表运行期,通过多态和类似于COM组件地方式进行检查。这种方式可以在运行期间检查接口是否具有某个函数,通过SearchInterface这类型地函数进行接口查找,再通过AddRef等函数返回对应接口地指针。这种方式通过动态多态地方式判断某个已经存在地C++对象,是否具有某个接口函数地实现。但该种方式是通过从逻辑层面的判断,并通过dynamic_cast进行转换而进行hasattr的怕判断。但并不能直接判断某一个类是否具有某个成员函数。

2、元编程std:: SFINAE + void_t判断,在元编程中,类型分为有效类型和无效类型。void类型在普通的C++中是一个不完整类型,不能直接声明void对象,因为编译器不知道void类型的大小。但对于函数返回值来说,void是一个有效的类型。对于C++模板元编程来说,void是一个有效的类型。可以通过SFINAE+void_t来判断一个成员函数或者成员的类型是否有效,从而实现hasattr类似的效果。

SFINAE: Substitution Failure Is Not An Error 有兴趣的话可以上网查。大概意思就是,在编译期,模板匹配的时候,编译器会一直匹配,知道匹配到一个最合适的特化或者偏特化,如果中间出现匹配失败的话,也不会停。

已下我们用SFINAE+std::void_t的方法来实现一个模板,用于判断类型是否具有my_test_func()成员,并支持const/non-const,左值/右值的判断。

template<typename T,typename = void>
constexpr bool has_my_test_func = false;

template<typename T>
constexpr bool has_my_test_func<T,std::void_t<decltype(
    std::declval<std::conditional_t<
        std::is_rvalue_reference_v<T>,
        std::remove_reference_t<T>&&,
        std::remove_reference_t<T>&>>().my_test_func()
    )>> = true;

上半部分为has_my_test_func的声明,下半部分为一个偏特化。当我们使用模板has_my_test_func<T>时,编译器会先去匹配下面的偏特化,如果能够成功通过void_t的有效类型检测,则应用到true值,若无法通过void_t的检测,则匹配到楼上的通用模板,值为false。

下面为测试代码:

class A{};
class B{private: void my_test_func();};
class C{public: void my_test_func();};
class D{public: int my_test_func();};
class E{public: void my_test_func()&;};
class F{public: void my_test_func()&&;};
class G{public: void my_test_func()const;};
class H{public: void my_test_func()const&&;};
    printf("%d\n",has_my_test_func<A>);         // 0
    printf("%d\n",has_my_test_func<B>);         // 0
    printf("%d\n",has_my_test_func<C>);         // 1
    printf("%d\n",has_my_test_func<D>);         // 1
    printf("%d\n",has_my_test_func<E>);         // 1
    printf("%d\n",has_my_test_func<E&&>);       // 0
    printf("%d\n",has_my_test_func<F>);         // 0
    printf("%d\n",has_my_test_func<F&&>);       // 1
    printf("%d\n",has_my_test_func<G>);         // 1
    printf("%d\n",has_my_test_func<const G>);   // 1
    printf("%d\n",has_my_test_func<H>);         // 0
    printf("%d\n",has_my_test_func<const H&>);  // 0
    printf("%d\n",has_my_test_func<const H&&>); // 1

标签:void,编程,C++,func,printf,test,my,class,hasattr
From: https://blog.csdn.net/qq_44377498/article/details/140776354

相关文章

  • c/c++ 《仿函数》
    4STL-函数对象4.1函数对象4.1.1函数对象概念概念:重载函数调用操作符的类,其对象常称为函数对象函数对象使用重载的()时,行为类似函数调用,也叫仿函数本质:函数对象(仿函数)是一个类,不是一个函数4.1.2函数对象使用特点:函数对象在使用时,可以像普通函数那样调用,可以......
  • 【论文解读】MetaGPT:用于元编程的多代理协作框架
    摘要基于大语言模型的多代理系统在解决自动化问题获得了显著进展。现有的基于大语言模型的多智能体系统已经可以解决简单的对话任务,但是对于更复杂的任务则因链式使用LLM导致的级联幻觉而导致逻辑不一致,从而变得复杂。在此,我们介绍MetaGPT,这是一种创新的元编程框架,将高效的......
  • 【C++】利用Eigen库实现弹道计算,并输出弹道轨迹
    利用Eigen库实现弹道计算,并输出弹道轨迹代码弹道知识简介:**弹道导弹**是指在火箭发动机推力作用下按预定程序飞行,关机后按自由抛物体轨迹飞行的导弹。其飞行弹道一般分为主动段和被动段:主动段(又称动力飞行段或助推段)是导弹在火箭发动机推力和制导系统作用下,从发射点......
  • 【C++的剃刀】我不允许你还不会AVL树
    ​ 学习编程就得循环渐进,扎实基础,勿在浮沙筑高台   循环渐进Forward-CSDN博客Hello,这里是kiki,今天继续更新C++部分,我们继续来扩充我们的知识面,我希望能努力把抽象繁多的知识讲的生动又通俗易懂,今天要讲的是C++AVL树~目录 循环渐进Forward-CSDN博客AVL树的......
  • 如何获取文件缩略图(C#和C++实现)
    在C++中,可以有以下两种办法使用COM接口IThumbnailCache文档链接:IThumbnailCache(thumbcache.h)-Win32apps|MicrosoftLearn示例代码如下:VOIDGetFileThumbnail(PCWSTRpath){HRESULThr=CoInitialize(nullptr);IShellItem*item=nullptr;hr=......
  • Lambda-Go:将函数式编程引入 Go
    Lambda-Go:将函数式编程引入Go原创 GoOfficialBlog GoOfficialBlog 2024年07月28日20:16 中国香港函数式编程是编程范式当中的一种,喜欢的人爱之如命,不喜欢的人嗤之以鼻,以简单高效著称的Go天然在函数式编程上有自己的优势。Lambda-Go[1] 是一个旨在将受Haskell......
  • 谁是开源之王?Mistral Large 2重磅发布,支持80多种编程语言
     Llama3.1登顶开源大模型王座仅仅过了一天,就被拉下了神坛,这次的主角是一家法国的团队MistralAI,发布了其最新旗舰模型MistralLarge2,这是一个具有1230亿参数的大型人工智能模型。该模型旨在增强代码生成、数学和推理能力,并支持超过80种编程语言。  模型信息数规模:12......
  • 编译期new,constexpr虚函数,C++
    标准:C++20环境:VSCodeg++13.2C++20新特性,constexpr虚函数,编译期new表达式,可以在编译期实现多态。示例代码://这段仅仅示例编译期new。structA{constexprA(){p=newint(6);}constexpr~A(){deletep;}constexprautoget()co......
  • Socket通信(C++)
    文章目录什么是SocketSocket通信过程C++Socket通信APIintsocket(intdomain,inttype,intprotocol);intbind(intsockfd,conststructsockaddr*addr,socklen_taddrlen);structsockaddrstructsockaddr_unstructsockaddr_in/structsockaddr_in6intconne......
  • C++自学笔记32(虚析构函数)
    在以往的笔记中我们讲到过析构函数和虚函数。析构函数是释放被初始化的变量,虚函数是告诉编译器有重名的函数被复写去派生类找对应函数。虚析构函数就是在基类析构函数前加入virtual表示派生类引用析构函数需要找派生类。看以下栗子。#include<iostream>classBase{publi......