如何在类成员模板函数定义中使用enable_if且避免重复声明
类外模板函数enable_if重载问题解决方法
现有结构体及成员模板函数声明如下:
struct Struct { template<typename T> void Foo(); }
想要在类外定义时用enable_if实现重载,且不想在结构体内部重复编写带enable_if的函数声明。尝试以下写法会报错(提示Struct无Foo<T>成员):
template<typename T> typename std::enable_if<std::is_class<T>::value,void>::type Struct::Foo() { ... } // error: Struct has no member `Foo<T>` template<typename T> typename std::enable_if<!std::is_class<T>::value,void>::type Struct::Foo() { ... } // error: Struct has no member `Foo<T>`
std::enable_if<std::is_class<T>::value,void>仅为示例,有没有无需在结构体内部编写多个带enable_if声明的实现方式?目前似乎只能采用这种方式:
struct Struct { template<typename T> typename std::enable_if<std::is_class<T>::value,void>::type Foo(); template<typename T> typename std::enable_if<!std::is_class<T>::value,void>::type Foo(); }
可行解决方案:模板参数默认值+SFINAE
不需要在类内声明多个重载,只保留原始的模板函数声明,在类外定义时通过给模板参数添加默认的enable_if约束来实现重载,具体代码如下:
类内声明(保持不变)
#include <type_traits> struct Struct { template<typename T> void Foo(); };
类外重载定义
// 处理类类型的重载 template<typename T, typename = typename std::enable_if<std::is_class<T>::value>::type> void Struct::Foo() { // 类类型的业务逻辑 } // 处理非类类型的重载 template<typename T, typename = typename std::enable_if<!std::is_class<T>::value>::type> void Struct::Foo() { // 非类类型的业务逻辑 }
原理说明
核心是利用**SFINAE(替换失败并非错误)**规则:当实例化Foo<T>时,编译器会尝试匹配两个模板定义,不符合enable_if条件的那个会因为模板参数替换失败被自动丢弃,不会触发编译错误。类内的原始声明template<typename T> void Foo()可以和这两个类外定义匹配,因为类外的模板参数默认值不影响声明与定义的匹配性。
注意事项
- 必须保证两个
enable_if的条件是互斥的,避免出现歧义匹配。 - 记得包含
<type_traits>头文件,才能使用std::enable_if和std::is_class这类类型特性工具。
内容的提问来源于stack exchange,提问作者M.kazem Akhgary
相关产品推荐
相关产品推荐

