3

I have the following code:

#include <iostream>
#include <type_traits>

template <typename T, typename std::enable_if
                                 <std::is_convertible<int, T>::value, T>::type>
void func(T a)
{
    std::cout << a << std::endl;
}

template <typename T, typename std::enable_if
                                 <!std::is_convertible<int, T>::value, T>::type>
void func(T a)
{
    a.print();
}

class Test
{
public:
    void print()
    {
        std::cout << "Test" << std::endl;
    }
};    

int main()
{
    func(3);
    func("Test");
    return 0;
}

With this code, I expected the first call to func to print out 3 (as int is indeed convertible to int, the first specialization should be called) and the second call to func to print out Test (Test() is not convertible to int, so the second specialization should be called). However, I instead get a compiler error:

prog.cpp: In function ‘int main()’:

prog.cpp:27:8: error: no matching function for call to ‘func(int)’

prog.cpp:5:6: note: candidate: template [class T, typename std::enable_if[std::is_convertible[int, T>::value, T>::type > void func(T)

prog.cpp:5:6: note: template argument deduction/substitution failed:

prog.cpp:27:8: note: couldn't deduce template parameter ‘[anonymous>’

If, however, I change the templated functions to instead be (while leaving everything else exactly the same):

template <typename T, typename std::enable_if
                                 <std::is_convertible<int, T>::value, T>::type* =
                                  nullptr>
void func(T a)
{
    std::cout << a << std::endl;
}

template <typename T, typename std::enable_if
                                 <!std::is_convertible<int, T>::value, T>::type* =
                                  nullptr>
void func(T a)
{
    a.print();
}

then everything compiles and works as I expected. What is this extra syntax doing and why do I need it?

Community
  • 1
  • 1
R_Kapp
  • 2,818
  • 1
  • 18
  • 32
  • duplicate of [How Does std::enable\_if work?](https://stackoverflow.com/questions/25284499/how-does-stdenable-if-work) – underscore_d Jul 07 '17 at 16:13

1 Answers1

8
template<typename T, typename std::enable_if<std::is_convertible<int, T>::value, T>::type>

if we were to remove the noise, would become

template<typename T, typename Something<T>::type>

which is declaring as its second parameter a non-type parameter, the typename here is specifying the nested type is a name of a type. See here for more information.

In the first case, the second parameter is non-type, so the function call func(3) doesn't fit the template which is expecting func<int, some_int>(3).

Passer By
  • 19,325
  • 6
  • 49
  • 96
  • @downvoter kindly explain, I am intrigued as to why this is perceived as downvote worthy – Passer By Jul 07 '17 at 16:06
  • 1
    You haven't answered the question. I noted in the question itself that providing a default parameter of `nullptr` solved the issue - why is the default parameter required? – R_Kapp Jul 07 '17 at 16:08
  • 1
    @R_Kapp I replied with the first three sentences. Everything below is added because I assumed you aren't familiar with SFINAE. – Passer By Jul 07 '17 at 16:10
  • The template parameter would result in a syntax error with or without the default argument correct (if the boolean in `std::enable_if` is `false`)? How does adding the default argument change things? – R_Kapp Jul 07 '17 at 16:15
  • I.e., instead of `template `, it would be `template `? – R_Kapp Jul 07 '17 at 16:17
  • @R_Kapp Yes, but then your template wouldn't fit with the function call – Passer By Jul 07 '17 at 16:21
  • Why does `std::enable_if, T>::type`, which should convert to `std::enable_if::type` for `T = int`, and then to `int` not fit the function call for `func(3);`? – R_Kapp Jul 07 '17 at 16:21
  • 1
    @R_Kapp Because the second parameter is non-type, you'd have to supply it with a value like `func<42>(3);`, but since it is the second parameter, you'd have to write `func(3)` – Passer By Jul 07 '17 at 16:22
  • To me, that last comment the answer in what I was not understanding with the syntax. That makes sense – R_Kapp Jul 07 '17 at 16:24
  • @R_Kapp Yeah, I totally misunderstood – Passer By Jul 07 '17 at 16:25