如何在C++14中用SFINAE检测类是否含模板成员函数Serialize
检测类是否拥有模板化的Serialize成员函数
问题背景
现有如下类:
class ArbitraryClass { public: template< typename T > void Serialize( T & obj ) { } };
需要编写代码检测传入的类是否拥有上述模板化的Serialize成员函数。尝试了以下C14代码(手动实现了C17的void_t):
// 手动实现C++17的void_t,因为C++14原生不支持 template < typename... Types > using void_t = void; template< typename T, typename = void > struct has_Serialize : std::false_type{}; template< typename T, void_t< decltype( std::declval<T>().template Serialize<T>( std::declval< int & >() ) ) > > struct has_Serialize<T> : std::true_type {}; static_assert( has_Serialize< ArbitraryClass >::value, "Has no Serialize" )
但代码执行失败,不确定用int&作为Serialize的参数替代类型是否正确,希望得到解决方法。
问题分析与修复
你的代码存在两个核心问题:
- 偏特化语法错误:偏特化的模板参数列表格式不符合要求,第二个参数需以默认参数形式声明,而非直接传入
void_t<...>。 - Serialize模板实参错误:你调用
Serialize<T>时,实参类型与函数参数的引用语义不匹配,且绑定了类自身类型,限制了检测的通用性。
修复后的代码
#include <type_traits> // 手动实现C++17的void_t template <typename... Types> using void_t = void; // 基础模板,默认判定为false template<typename T, typename = void> struct has_Serialize : std::false_type {}; // 偏特化:检测类是否拥有可接受int&参数的模板化Serialize template<typename T> struct has_Serialize<T, void_t< decltype(std::declval<T>().template Serialize<int>(std::declval<int&>())) >> : std::true_type {}; // 测试用例 class ArbitraryClass { public: template<typename T> void Serialize(T& obj) {} }; class NoSerializeClass {}; static_assert(has_Serialize<ArbitraryClass>::value, "ArbitraryClass should have Serialize"); static_assert(!has_Serialize<NoSerializeClass>::value, "NoSerializeClass should not have Serialize");
关键说明
- SFINAE机制生效条件:偏特化时必须将
void_t<...>作为第二个模板参数的默认值,这样当decltype内的表达式合法时,才会匹配该偏特化版本,否则回退到基础模板。 - 模板成员函数调用语法:
std::declval<T>().template Serialize<U>(...)中的template关键字必须保留,因为Serialize是依赖于T的模板成员函数,需要明确告知编译器这是模板调用。 - 参数类型选择:用
int&作为测试参数是合理的,只要目标类的Serialize能接受任意非const引用类型,检测就能通过。如果需要更通用的检测(比如支持任意类型参数),可以将实参改为decltype(std::declval<int&>()),让编译器自动推导匹配。
内容的提问来源于stack exchange,提问作者ScaryAardvark
相关产品推荐
相关产品推荐

