基于std :: is_convertible的std :: enable_if无法正确推断模板

R_K*_*app 1 c++ enable-if

我有以下代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

使用此代码,我希望第一个调用func打印输出3int实际上可以转换为int,应该调用第一个专业化名称),第二个调用func打印输出TestTest()不能转换为int,所以应该调用第二个专业化名称)。但是,我得到了一个编译器错误:

prog.cpp:在函数'int main()'中:

prog.cpp:27:8:错误:没有匹配的函数调用'func(int)'

prog.cpp:5:6:注意:候选:模板[类T,类型名称std :: enable_if [std :: is_convertible [int,T> :: value,T> :: type> void func(T)

prog.cpp:5:6:注意:模板参数推导/替换失败:

prog.cpp:27:8:注意:无法推断出模板参数'[anonymous>'

但是,如果我将模板化的函数更改为(在使其他所有内容完全相同的同时)是:

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();
}
Run Code Online (Sandbox Code Playgroud)

然后一切都会按照我的预期进行编译和工作。这种额外的语法在做什么,为什么我需要它?

Pas*_* By 6

template<typename T, typename std::enable_if<std::is_convertible<int, T>::value, T>::type>
Run Code Online (Sandbox Code Playgroud)

如果我们要消除噪音,

template<typename T, typename Something<T>::type>
Run Code Online (Sandbox Code Playgroud)

它声明非类型参数作为其第二个参数,typename此处指定嵌套type是类型的名称。有关更多信息,请参见此处

在第一种情况下,第二个参数是非类型的,因此函数调用func(3)不适合期望的模板func<int, some_int>(3)