这是模板的正确行为吗?

tej*_*jas 6 c++ templates

template<class blah, class bleh>
blah func(bleh p)
{
    // Do something
}

int main()
{
    double d=1.111;
    int i = func<int>(d); // #1
    int j = func<int,double>(d); // #2
    // ....
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中func,#1和#2 的实例都在编译,但我不确定什么是正确的,以及为什么.

有人可以解释为什么#1是正确的,也许给一些背景?

Nia*_*all 10

是的,这是正确的行为.

案例1 - 类型扣除

func<int>(d);
Run Code Online (Sandbox Code Playgroud)

这使用模板类型推导来确定其类型bleh.

为了实例化一个函数模板,必须知道每个模板参数,但不是必须指定每个模板参数.如果可能,编译器将从函数参数推断出缺少的模板参数.尝试进行函数调用时以及执行函数模板的地址时会发生这种情况.

编译器将类型d视为a double,因此推导出的实际类型bleh也必须是a double.

来自cppreference,也包含在C++规范的第14.8.2节中;

模板参数推导尝试确定模板参数...,可以将其替换为每个参数P以生成推导出的类型A,这与参数的类型相同A,....

如果有多个参数,则分别推导出每个P/ A对,然后组合推导出的模板参数.如果演绎失败或对任何P/ A对不明确,或者如果不同的对产生不同的推导模板参数,或者如果任何模板参数既未推断也未明确指定,则编译失败.

案例2

func<int,double>(d);
Run Code Online (Sandbox Code Playgroud)

类型为bleh显式设置double,因此编译器会这样做.d提供了参数,因为它也是一个double,编译器很乐意继续.如果一个参数(即代替d)提供的类型不是double,或者不能隐式转换为double(例如通过促销,非显式构造函数或用户提供的转换),这将导致错误.