Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SFINAE working in return type but not as template parameter

I already used the SFINAE idiom quite a few times and I got used to put my std::enable_if<> in template parameters rather than in return types. However, I came across some trivial case where it didn't work, and I'm not sure why. First of all, here is my main:

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

Here is an implementation of foo that triggers the error:

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"; } 

And here is a supposedly equivalent piece of code that works fine:

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"; } 

My question is: why does the first implementation of foo triggers that error while the second one does not trigger it?

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>           ^ 

EDIT :

Working code and faulty code.

like image 722
Morwenn Avatar asked Mar 15 '13 08:03

Morwenn


People also ask

Can we pass Nontype parameters to templates?

Template non-type arguments in C++It is also possible to use non-type arguments (basic/derived data types) i.e., in addition to the type argument T, it can also use other arguments such as strings, function names, constant expressions, and built-in data types.

What is correct for template parameter?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)

Can template have default parameters?

You cannot give default arguments to the same template parameters in different declarations in the same scope. The compiler will not allow the following example: template<class T = char> class X; template<class T = char> class X { };

Can a template parameter be a function?

A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.


1 Answers

You should take a look at 14.5.6.1 Function template overloading (C++11 standard) where function templates equivalency is defined. In short, default template arguments are not considered, so in the 1st case you have the same function template defined twice. In the 2nd case you have expression referring template parameters used in the return type (again see 14.5.6.1/4). Since this expression is part of signature you get two different function template declarations and thus SFINAE get a chance to work.

like image 167
Konstantin Oznobihin Avatar answered Oct 08 '22 02:10

Konstantin Oznobihin