为什么函数参数的类型推导优先于模板中的类型?

问题描述

让我们看一下enable_if用法的简单示例

template <bool,typename T = void>
struct enable_if
{
};

template <typename T>
struct enable_if<true,T>
{
    typedef T type;
};
  1. 此处预计 y 将是 int,因为 T 是我们的“已启用”类型。
template <typename T,typename Y = typename std::enable_if<std::is_integral<T>::value,T>::type>
void do_stuff(T t)
{
    (void)t;
    Y y;
    std::cout << typeid(y).name() << std::endl;
}
do_stuff(15); // int
  1. 但这里的事情对我来说有些不明确,y 将被推导出为实际参数的类型
template <typename T,T>::type>
void do_stuff(T t,Y y)
{
    (void)t;
    std::cout << "do_stuff integral\n";
    std::cout << typeid(y).name() << std::endl;
}

do_stuff(15,14.3);  // double

所以我的问题是:

强制编译器优先从传递的实际参数中推导 y 并忽略 type 中启用的 enable_if 的规则是什么?

解决方法

默认模板参数仅在未明确指定模板参数且无法推导出模板参数时使用。对于这种情况,Y 可以从 14.3 推导出为 double,然后将不使用默认参数。同样,在第一个示例中,您也可以通过指定模板参数来绕过 std::enable_if 的检查。

do_stuff<int,double>(15); // double

顺便说一句,您可以在类型声明中使用 std::enable_if 添加非类型模板参数,以使检查始终生效。

template <typename T,typename Y,typename std::enable_if<std::is_integral<T>::value,T>::type* = nullptr>
void do_stuff(T t,Y y)