SFINAE工作返回types,但不作为模板参数

我已经使用了SFINAE成语很多次了,我习惯于将std::enable_if<>放在模板参数中,而不是返回types中。 然而,我遇到了一个不起作用的小事,我不知道为什么。 首先,这是我的主要:

 int main() { foo(5); foo(3.4); } 

这里是触发错误的foo的实现:

 template<typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type> auto foo(T) -> void { std::cout << "I'm an integer!\n"; } template<typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type> auto foo(T) -> void { std::cout << "I'm a floating point number!\n"; } 

这是一个可以正常工作的代码:

 template<typename T> auto foo(T) -> typename std::enable_if<std::is_integral<T>::value>::type { std::cout << "I'm an integrer!\n"; } template<typename T> auto foo(T) -> typename std::enable_if<std::is_floating_point<T>::value>::type { std::cout << "I'm a floating point number!\n"; } 

我的问题是:为什么第一个执行foo触发该错误,而第二个不触发?

 main.cpp:14:6: error: redefinition of 'template<class T, class> void foo(T)' auto foo(T) ^ main.cpp:6:6: note: 'template<class T, class> void foo(T)' previously declared here auto foo(T) ^ main.cpp: In function 'int main()': main.cpp:23:12: error: no matching function for call to 'foo(double)' foo(3.4); ^ main.cpp:6:6: note: candidate: template<class T, class> void foo(T) auto foo(T) ^ main.cpp:6:6: note: template argument deduction/substitution failed: main.cpp:5:10: error: no type named 'type' in 'struct std::enable_if<false, void>' typename = typename std::enable_if<std::is_integral<T>::value>::type> ^ 

编辑

工作代码和错误的代码 。

你应该看看14.5.6.1 Function template overloading (C ++ 11标准),其中定义了函数模板的等价性。 简而言之,默认的模板参数是不被考虑的,所以在第一种情况下,你有相同的函数模板定义两次。 在第二种情况下,您有expression式引用返回types中使用的模板参数(请参阅14.5.6.1/4)。 由于这个expression式是签名的一部分,所以你得到两个不同的函数模板声明,从而SFINAE有机会工作。

该模板的= ...只是给出一个默认参数。 这不是实际签名的一部分

 template<typename T, typename> auto foo(T a); 

两个function。

根据您的需求,这个问题的最通用的解决scheme是使用标签调度。

 struct integral_tag { typedef integral_tag category; }; struct floating_tag { typedef floating_tag category; }; template <typename T> struct foo_tag : std::conditional<std::is_integral<T>::value, integral_tag, typename std::conditional<std::is_floating_point<T>::value, floating_tag, std::false_type>::type>::type {}; template<typename T> T foo_impl(T a, integral_tag) { return a; } template<typename T> T foo_impl(T a, floating_tag) { return a; } template <typename T> T foo(T a) { static_assert(!std::is_base_of<std::false_type, foo_tag<T> >::value, "T must be either floating point or integral"); return foo_impl(a, typename foo_tag<T>::category{}); } struct bigint {}; template<> struct foo_tag<bigint> : integral_tag {}; int main() { //foo("x"); // produces a nice error message foo(1); foo(1.5); foo(bigint{}); } 

模板中的值工作:

 template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0> auto foo(T) -> void { std::cout << "I'm an integer!\n"; } template<typename T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0> auto foo(T) -> void { std::cout << "I'm a floating point number!\n"; }