为何简单SFINAE示例编译失败?MSVC报C2995错误
为什么MSVC会报我的SFINAE函数模板重复定义?
你写的这段代码:
template<typename T, typename = std::enable_if_t<std::is_trivially_copyable<T>::value>> inline int test_sfinae(T tc) { return 1; } template<typename T, typename = std::enable_if_t<!std::is_trivially_copyable<T>::value>> inline int test_sfinae(T ntc) { return 2; }
在MSVC下触发了C2995 'int test_sfinae(T)': function template has already been defined错误,核心原因是C++标准中,函数模板的签名不包含默认模板参数。
具体解释:
这两个函数模板的模板参数列表本质上都是template<typename T, typename>,后面的= ...只是默认参数,不属于模板签名的一部分。对编译器来说,这两个模板的“身份标识”完全相同——都是接受一个类型参数T和一个匿名类型参数的函数模板,函数参数都是T,返回值都是int。哪怕默认参数的SFINAE条件是互斥的,编译器在处理模板定义时,会先判定这是同一个模板的重复定义,直接报错,根本不会走到SFINAE的筛选阶段。
修正方法(几种常见的正确SFINAE写法):
1. 将enable_if放到函数参数中
通过给函数添加一个带默认值的指针参数,把SFINAE条件绑定到参数类型上:
#include <type_traits> template<typename T> inline int test_sfinae(T tc, std::enable_if_t<std::is_trivially_copyable<T>::value>* = nullptr) { return 1; } template<typename T> inline int test_sfinae(T ntc, std::enable_if_t<!std::is_trivially_copyable<T>::value>* = nullptr) { return 2; }
2. 将enable_if作为模板的非默认参数
把条件作为模板参数的一部分,用一个默认值(比如0)来占位,这样两个模板的签名就不一样了:
#include <type_traits> template<typename T, std::enable_if_t<std::is_trivially_copyable<T>::value, int> = 0> inline int test_sfinae(T tc) { return 1; } template<typename T, std::enable_if_t<!std::is_trivially_copyable<T>::value, int> = 0> inline int test_sfinae(T ntc) { return 2; }
3. 将enable_if放到返回值类型中
直接把返回值类型和SFINAE条件绑定,这样两个模板的返回值类型(在有效实例化时)不同,签名自然区分开:
#include <type_traits> template<typename T> inline std::enable_if_t<std::is_trivially_copyable<T>::value, int> test_sfinae(T tc) { return 1; } template<typename T> inline std::enable_if_t<!std::is_trivially_copyable<T>::value, int> test_sfinae(T ntc) { return 2; }
这几种写法都能让MSVC正确识别两个模板的差异,同时通过SFINAE实现对平凡可拷贝/非平凡可拷贝类型的区分。
内容的提问来源于stack exchange,提问作者Igor Mitrovic
相关产品推荐
相关产品推荐

