std::enable_if 基于 std::is_convertible 未正确推导模板

std::enable_if predicated on std::is_convertible not deducing template correctly

我有以下代码:

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

使用这段代码,我预计第一次调用 func 会打印出 3(因为 int 确实可以转换为 int,第一个特化应该是调用)和第二次调用 func 打印出 TestTest() 不能转换为 int,所以应该调用第二个特化)。但是,我得到了一个编译器错误:

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

但是,如果我将模板函数更改为(同时保持其他一切完全相同):

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();
}

然后一切都按我预期的那样编译和工作。这个额外的语法有什么用,我为什么需要它?

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

如果我们去除噪音,会变成

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

声明它的第二个参数是一个非类型参数,这里的 typename 指定嵌套的 type 是一个类型的名称。有关详细信息,请参阅 here

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

的模板