Search code examples
c++templatesc++11sfinaeenable-if

Why don't either of these function templates match the instantiations?


The following code fails to compile with Intel C++ 2013.

#include <type_traits>
#include <iostream>


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

template <
    typename T, 
    typename std::enable_if<!std::is_integral<T>::value>::type
>
void myfunc( T a) 
{ 
    std::cout << a << std::endl;
}




int main()
{
    double a;
    int b;
    myfunc(a);
    myfunc(b);

    return 0;

}

Here is the error output:

ConsoleApplication1.cpp(33): error : no instance of overloaded function "myfunc" matches the argument list
1>              argument types are: (double)
1>      myfunc(a);
1>      ^
1>  
1>ConsoleApplication1.cpp(34): error : no instance of overloaded function "myfunc" matches the argument list
1>              argument types are: (int)
1>      myfunc(b);
1>      ^
1>  

Where am I going wrong?


Solution

  • The usual and correct way to use enable_if in a function is to stick it in the return type.

    template <typename T>
    typename std::enable_if<std::is_integral<T>::value>::type myfunc(T a) {
        std::cout << a << " (integral)" << std::endl;
    }
    
    template <typename T>
    typename std::enable_if<!std::is_integral<T>::value>::type myfunc(T a) {
        std::cout << a << " (non-integral)" << std::endl;
    }
    

    For your variant, the correct way is:

    template <typename T,
              typename = typename std::enable_if<std::is_integral<T>::value>::type>
    void myfunc(T a) {
        std::cout << a << " (integral)" << std::endl;
    }
    

    ... the "enable_if" is a default template argument. And it does not work in your case because that function is not overloaded.