使用SFINAE检测模板类是否存在指定成员的实现方法
问题原因
你的代码有三个核心错误,导致SFINAE检测失效:
- 主模板与偏特化签名不匹配:主模板第一个参数定义为模板模板参数,偏特化时却传入实例化后的具体类型,编译器无法完成模板匹配
- 偏特化、函数模板中使用的
KeyType没有提前在模板参数列表中声明,属于未定义标识符 - SFINAE约束位置、
has_psl传参逻辑错误:你给has_psl传入的是未实例化的模板,但是成员检测必须基于实例化后的具体类型才能生效
修正方案
不需要专门为模板类写模板模板参数版本的检测元函数,直接实现支持任意类型的通用成员检测即可,兼容性更强,代码更简洁:
#include <type_traits> #include <cstddef> // 待检测的目标模板类 template <typename KeyType> struct RawBytesEntry { bool used = false; size_t psl = 0; KeyType key; }; // has_psl主模板:默认判定为不存在psl成员 template <typename T, typename = void> struct has_psl : std::false_type {}; // 偏特化:当类型T存在psl成员时匹配此版本 template <typename T> struct has_psl<T, std::void_t<decltype(&T::psl)>> : std::true_type {}; // 带编译期约束的f函数:仅接收带psl成员的类型指针 template <typename Entry> std::enable_if_t<has_psl<Entry>::value, bool> f(Entry* buffer, size_t offset, Entry* new_entry) { // 此处编写函数业务逻辑 return true; }
调用时直接传入RawBytesEntry<任意KeyType>的指针即可正常编译,如果传入没有psl成员的类型,编译器会直接报无匹配函数错误,完全符合需求。
如果你确实需要在元函数中拿到模板类的KeyType等模板参数,可以使用模板模板参数的专用版本:
// 适配单类型参数模板类的检测元函数 template <template <typename> typename EntryType, typename KeyType, typename = void> struct has_psl_tmpl : std::false_type {}; template <template <typename> typename EntryType, typename KeyType> struct has_psl_tmpl<EntryType, KeyType, std::void_t<decltype(&EntryType<KeyType>::psl)>> : std::true_type {}; // 对应函数模板实现 template <template <typename> typename EntryType, typename KeyType, typename = std::enable_if_t<has_psl_tmpl<EntryType, KeyType>::value>> bool f_tmpl(EntryType<KeyType>* buffer, size_t offset, EntryType<KeyType>* new_entry) { return true; }
实现细节提示:使用
decltype(&T::psl)取成员指针的写法,比直接写decltype(T::psl)兼容性更好,不会因为静态成员、成员类型的歧义触发编译错误,只要类型存在名为psl的成员就能正确匹配。
内容的提问来源于stack exchange,提问作者Arthur M
相关产品推荐
相关产品推荐

