如何实现编译时检查类型是否包含特定成员的通用方案?
通用编译期成员检测方案:摆脱宏与重复代码
嘿,这个需求太贴合实际了——谁愿意为了每一个成员检查都写一堆重复的模板或者宏啊!咱完全可以实现你想要的那种has<Type, Member>::value式的通用检测,不用再搞那些繁琐的DEFINE_MEMBER_CHECK宏了。下面分C++版本给你拆解实现思路:
一、C++11/14/17通用实现(无宏)
核心思路是利用SFINAE(替换失败不是错误)和void_t(C17自带,C11可以自己实现)来做编译期判断,只需要写一次模板就能检测任意成员(变量/函数):
1. 基础模板与void_t实现
首先定义一个默认返回false的基础模板,再用特化版本匹配成员存在的情况:
// C++11需要自己实现void_t,C++17直接用std::void_t template <typename...> using void_t = void; // 基础模板:默认成员不存在 template <typename T, typename Member, typename = void> struct has : std::false_type {}; // 特化模板:当成员存在时,返回true template <typename T, typename Member> struct has<T, Member, void_t<decltype(std::declval<T>().*Member)>> : std::true_type {}; // C++14及以上可以加个变量模板,简化使用 template <typename T, typename Member> constexpr bool has_v = has<T, Member>::value;
2. 使用示例
不管是成员变量还是成员函数,只要传递对应的成员指针类型就行:
struct MyClass { int num; void print() {} // 重载函数示例 int add(int a) { return a + 1; } double add(double a) { return a + 2.0; } }; // 检查成员变量num constexpr bool has_num = has_v<MyClass, decltype(&MyClass::num)>; // true // 检查无重载的成员函数print constexpr bool has_print = has_v<MyClass, decltype(&MyClass::print)>; // true // 检查重载函数add:需要明确指定签名避免歧义 using AddIntFunc = int(MyClass::*)(int); constexpr bool has_add_int = has_v<MyClass, AddIntFunc>; // true // 检查不存在的成员 constexpr bool has_none = has_v<MyClass, decltype(&MyClass::nonexist)>; // false
二、C++20更优雅的Concepts实现
如果你的项目已经用上C++20,用Concepts可以让代码更直观易读:
template <typename T, typename Member> concept has_member = requires(T t) { t.*Member; // 编译期检查:T的对象能否访问该成员 }; // 使用时直接用static_assert或者在模板约束里用 static_assert(has_member<MyClass, decltype(&MyClass::num)>); static_assert(has_member<MyClass, decltype(&MyClass::print)>); // 模板约束示例 template <typename T> requires has_member<T, decltype(&T::num)> void process(T obj) { // 这里可以安全访问obj.num }
关键原理说明
std::declval<T>():编译期生成一个T类型的临时对象引用,不用构造函数就能模拟成员访问void_t:用来触发SFINAE——如果decltype(...)里的表达式合法(成员存在),就会匹配特化模板,否则用基础模板- 成员指针:不管是变量还是函数,都可以用
&Class::member获取指针类型,作为模板参数传递
这种方式完全不需要为每个检查写宏或者复制模板代码,一次定义就能通用所有成员检测,完美符合你想要的简洁语法!
内容的提问来源于stack exchange,提问作者Holden Perkins
相关产品推荐
相关产品推荐

