#include <iostream>
#include <string>
template <typename T>
void f(T x = std::string{""})
{
std::cout << '[' << x << ']' << std::endl;
}
int main()
{
f(23); // Case 1: Doesn't fail
f<int>(); // Case 2: Compilation error
f<int>(23); // Case 3: Doesn't fail
}
不应该情况1和案例3也失败,因为函数模板是由int
实例化的,耳聋值的类型是std::string
。
发布于 2018-08-28 05:21:44
情况1和案例3不应该也失败吗?因为函数模板是由int实例化的,耳聋值的类型是std::string?
不,不应该。请看下面的原因。如果您希望它失败,那么您应该将template.定义为正则函数,接收std::string
类型的参数,而不是函数。
您所拥有的是默认参数实例化的情况,参见[temp.inst]中的
如果函数模板
f
的调用方式要求使用默认参数,则查找相关名称,检查语义约束,并实例化.如果默认参数是函数模板专门化中使用的初始化器,则.这种分析称为默认参数实例化。实例化的默认参数然后用作f
. 的参数。
当你写:
template <typename T>
void f(T x = std::string{""}){...}
这意味着""
是x
的默认参数,只有在调用没有任何参数()的情况下。例如,在您的案例2中。
您的模板函数被定义为对int
或其他各种类型都很好地进行了安装。
例如这里(案例1)
f(23);
它被隐式地(通过基于参数类型的推理)实例为f<int>()
,因为23
在规范中被定义为int
文本。类型为x
的参数int
接收在调用站点中提供的23
的非默认值。
在这里(案例2)
f<int>();
正是上面的标准子句发挥作用的地方:成功地实例化了f()
,但没有为它提供参数,因此实例化的默认参数随后被用作f
的参数。因此编译失败,因为参数x
的默认值被定义为std::string
,没有将其转换为int
类型。它实际上相当于在声明为f("")
void f(int x)
.的函数上调用。
在这里(案例3)
f<int>(23);
再次显式,这次是,您在调用站点.上提供了正确的参数类型。
发布于 2018-08-28 05:15:43
只有在没有为T x = std::string{""}
提供arg的情况下才执行x
。
f(23)
隐式实例化到f<int>
。不使用x
的默认值,因为23
是作为int
文本提供的。
f<int>()
现在,T
是int
类型的,但是您要用一个std::string
分配给x
f<int>(23)
T
仍然是int
,与案例1相同
发布于 2018-08-28 06:49:36
@Abigail提供的答案解释了为什么case 1和3没有失败,另外让我指出函数模板没有多大意义。一个具有默认值的参数的函数应该是可调用的,如:
void g(std::string = "") { /* ... */ }
g(); // Use default parameter
g("non-default");
相反,可以用给定的参数调用函数模板。
f("non-default");
但不是没有任何参数,因为编译器不会从默认参数中推断模板类型。
f(); // Doesn't compile
我建议将模板更改为
template <typename T = std::string>
void f(T x = T{})
{
// same as before
}
它修复了f()
实例化。
https://stackoverflow.com/questions/52050458
复制相似问题