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; //输出: true
    constexpr bool bA2 = has_member_ex_getDataSize<A2>::value; //输出: false
    constexpr bool bA3 = has_member_ex_getDataSize<A3>::value; //输出: false

    return 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; //输出: true
    constexpr bool bA2 = has_non_static_member_ex_getDataSize<A2>::value; //输出: true
    constexpr bool bA3 = has_non_static_member_ex_getDataSize<A3>::value; //输出: false

    return 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++模板函数重载规则细说

  • 12
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值