C++反射之检测struct或class是否实现指定函数

目录

1.引言

2.检测结构体或类的静态函数

3.检测结构体或类的成员函数

3.1.方法1

3.2.方法2


1.引言

        诸如Java, C#这些语言是设计的时候就有反射支持的。c++没有原生的反射支持。并且,c++提供给我们的运行时类型信息非常少,只是通过typeinfo提供了有限的一些支持。这一点点支持其实连类型名都无法打印好。更别说去检测一个结构体或类是否具有实现指定函数。

        通过编写模板代码和std::enable_ifrequires(C++20)表达式,你可以根据某个类型是否拥有特定的成员函数或方法来启用或禁用某些代码。这种方法不会直接告诉你一个类型是否实现了某个函数,但它允许你根据类型的能力编写条件编译的代码。如:

template<typename T, typename = void>  
struct has_func_impl : std::false_type {};  template<typename T>  
struct has_func_impl<T, std::void_t<decltype(std::declval<T&>().func())>> : std::true_type {};  template<typename T>  
constexpr bool has_func_v = has_func_impl<T>::value;  // 使用示例  
struct MyClass {  void func() {}  
};  static_assert(has_func_v<MyClass>); // 成功

2.检测结构体或类的静态函数

C++之std::declval-CSDN博客

1)通过编写一个模板结构和它的特化版本来检测是否存在某个成员函数。

2)使用std::declval来在编译时模拟对成员函数的调用。

3)如果调用成功,则特化版本继承自std::true_type,否则继承自std::false_type

代码如下:

#define HAS_MEMBER_EX(member)\
template<typename T, typename... Args> struct has_member_ex_##member{\
private:\template<typename U> \static auto Check(int) -> decltype(U::member(std::declval<Args>()...), std::true_type()); \template<typename U> \static std::false_type Check(...); \
public:\enum { value = std::is_same<decltype(Check<T>(0)), std::true_type>::value }; \
}; \HAS_MEMBER_EX(getDataSize)

测试代码:

//A1具有静态getDataSize()函数
class A1{
public:static int getDataSize() {return 100;}
};//A2只有成员函数getDataSize()函数
class A2{
public:int getDataSize() {return 100;}
};//A3无函数
class A3{};int main()
{constexpr bool bA1 = has_member_ex_getDataSize<A1>::value; //输出: trueconstexpr bool bA2 = has_member_ex_getDataSize<A2>::value; //输出: falseconstexpr bool bA3 = has_member_ex_getDataSize<A3>::value; //输出: falsereturn 0;
}

3.检测结构体或类的成员函数

3.1.方法1

也是利用std::declval结合decltype来判断是否具有某个函数,代码如下:

#define HAS_NON_STATIC_MEMBER_EX(member)\
template<typename T, typename... Args> struct has_non_static_member_ex_##member{\
private:\template<typename U> \static auto Check(int) -> decltype(std::declval<U>()().member(std::declval<Args>()...), std::true_type()); \template<typename U> \static std::false_type Check(...); \
public:\enum { value = std::is_same<decltype(Check<T>(0)), std::true_type>::value }; \
}; \HAS_NON_STATIC_MEMBER_EX(getDataSize)

  测试代码:

//A1,A2,A3同上,省略int main()
{constexpr bool bA1 = has_non_static_member_ex_getDataSize<A1>::value; //输出: trueconstexpr bool bA2 = has_non_static_member_ex_getDataSize<A2>::value; //输出: trueconstexpr bool bA3 = has_non_static_member_ex_getDataSize<A3>::value; //输出: falsereturn 0;
}

        我们使用std::declval<U>()::member()来尝试“调用”该类型的member成员函数(而不需要创建一个实际的对象)。如果这行代码在编译时有效(即U类型有一个无参数且返回类型为可推导的member成员函数),那么我们就特化Check()std::true_type;否则,我们保持其默认实现为std::false_type

3.2.方法2

实现代码如下:

#define HAS_NON_STATIC_MEMBER_EX1(R, member) \
template<typename T> struct has_non_static_member_ex1_##member{ \
private:\template<typename Y, Y y>	\class Helper;	\template<typename U = T>	\constexpr static bool has##member(...) {\return false;\}\template<typename U = T>\constexpr static bool has##member(Helper<R (U::*)()const, &U::member>*) {\return true;\}\
public:\static const bool value = has##member<T>(nullptr);\
};\HAS_NON_STATIC_MEMBER_EX1(int, getDataSize)

测试代码同上。

推荐阅读

C++之std::declval

C++模板函数重载规则细说

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/679247.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入了解 NumPy:深度学习中的数学运算利器

文章目录 1. 导入NumPy2. 创建NumPy数组3. 数组的算术运算4. N维数组4.1 创建和操作多维数组4.2 高维数组 5. NumPy的广播功能5.1 基本广播示例5.2 更复杂的广播示例 6. 访问数组元素6.1 基于索引的访问6.2 遍历数组6.3 基于条件的访问6.4 高级索引6.5 性能考虑 在深度学习和数…

基于java,SpringBoot和Vue的智慧校园在线考试留言讨论系统设计

摘要 基于Java, SpringBoot和Vue的智慧校园在线考试留言讨论系统是一个为现代教育需求定制的Web应用&#xff0c;它结合了最新的前后端技术来提供一个互动性强、用户友好的学习和交流平台。该系统旨在通过提供实时留言和讨论功能&#xff0c;增进学生间的互动以及师生之间的沟…

Java数组的使用

前言 这里我使用的是IDEA编译器进行演示 数组的创建与初始化 创建格式&#xff1a; T[] 数组名 new T[N] T表示数组存放的数据类型&#xff0c;N表示数组的大小。 T[] 表示数组的类型。 这里要注意和C语言不同的是C语言使用类似int arr[10]这样的结构进行创建数组&#xff0c…

时序图详解

1.这是iic总线在回应时候的时序图&#xff0c;data in代表eeprom收到数据&#xff0c;回stm32的ack&#xff0c;数据回应&#xff0c;data out代表stm32收到eeprom的消息&#xff0c;数据输出ack回应 2.交叉线 代表在这一次输出高电平&#xff0c;或者在这一次也可能输出低电…

【bash】笔记

在Shell脚本中&#xff0c;-e 是一个测试运算符&#xff0c;用于检查给定的文件或目录是否存在。 | 是通道符&#xff0c;会把前面的输出给后面作为输入。 sudo tee命令在这里用于同时更新文件和在终端显示输出&#xff08;尽管 > /dev/null 将标准输出重定向到黑洞&…

windows11忘记登录密码怎么办?

STEP1&#xff1a;进入Win RE界面 1.按住shift不要松手,点击重新启动&#xff0c;进入WINRE界面 2.选择疑难解答 选择高级选项 点击命令提示符 STEP2:替换utilman 1.输入以下代码查看所在windows所在盘 diskpart list volume exit 2.根据所在盘输入命令&#xff08;以C盘为…

全面的Partisia Blockchain 生态 4 月市场进展解读

Partisia Blockchain 是一个以高迸发、隐私、高度可互操作性、可拓展为特性的 Layer1 网络。通过将 MPC 技术方案引入到区块链系统中&#xff0c;以零知识证明&#xff08;ZK&#xff09;技术和多方计算&#xff08;MPC&#xff09;为基础&#xff0c;共同保障在不影响网络完整…

射频无源器件之巴伦

一. 巴伦的作用 Balun,balanced-unbalanced的缩写,即平衡-不平衡转换器,是一种三端口无源器件,其本质是通过电感线圈的相互耦合实现的信号转换。用于平衡信号(差分信号,即振幅相等、相位相差180 的两个信号)与非平衡信号(单端信号)的相互转换。 Balun是高频电路重要器…

分成互质组

题目描述: 给定 n 个正整数&#xff0c;将它们分组&#xff0c;使得每组中任意两个数互质。 至少要分成多少个组&#xff1f; 输入格式 第一行是一个正整数 n。 第二行是 n 个不大于10000的正整数。 输出格式 一个正整数&#xff0c;即最少需要的组数。 #include<iostream…

Navicat导出表结构到Excel或Word

文章目录 sql语句复制到excel复制到Word sql语句 SELECTcols.COLUMN_NAME AS 字段,cols.COLUMN_TYPE AS 数据类型,IF(pks.CONSTRAINT_TYPE PRIMARY KEY, YES, NO) AS 是否为主键,IF(idxs.INDEX_NAME IS NOT NULL, YES, NO) AS 是否为索引,cols.IS_NULLABLE AS 是否为空,cols.…

华火电焰灶,科技打造“新”厨房

家里最大的空气污染源其实来自厨房里的燃气灶&#xff01;——斯坦福大学发表的《科学进展》期刊 厨房在家庭中占有举足轻重的地位&#xff0c;它不仅是一个烹饪美食的场所&#xff0c;更是家人情感交流的重要空间。厨房大致经历了两次变革&#xff0c;分别是以柴火灶为主体的厨…

小程序支付的款项流转与到账时间

商家做小程序&#xff0c;最关心的是客户通过小程序下单支付的钱&#xff0c;是怎么样的流转状态以及最终到哪里。因此&#xff0c;本文将详细解析款项最终流向何处以及多久能够到账。 一、小程序支付的款项流向 当用户在小程序内完成支付后&#xff0c;款项并不会直接到达商…