我有以下工作代码,预期输出。
#include <iostream>
template <typename T>
T twice(T in)
{
return 2*in;
}
struct Foo
{
Foo operator+(int (*func)(int in)) const
{
Foo ret{data};
ret.data += func(ret.data);
return ret;
}
int data;
};
int main()
{
Foo f1{20};
Foo f2 = f1 + twice;
Foo f3 = f1 + twice<int>;
std::cout << f2.data << std::endl;
std::cout << f3.data << std::endl;
}
直到昨天我才知道即使没有参数,编译器也可以推断出函数模板的类型参数。在上面的代码中,表达式
f1 + twice
和
f1 + twice<int>
导致相同的值。
我的问题是:在C ++ 03 / C ++ 11标准中,我们可以为编译器的自动类型检测逻辑找到必要的支持文档吗?
答案 0 :(得分:4)
C ++ 11 14.8.2.2模板参数可以从获取重载函数地址时指定的类型推导出来。
此处,参数类型operator+
指定的类型为int (*)(int)
,重载函数为twice
,因此推导出int
作为模板参数匹配功能类型。如果您需要该扣除的血腥细节,请参见14.8.2.5。
答案 1 :(得分:3)
这与实际的c ++ 11标准最接近,但我发现的草案仍然是公开可用的版本:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf。
我相信在您编写Foo f2 = f1 + twice;
并将twice
作为函数地址传递时,会完成模板参数推导。 twice
作为函数的地址传递给operator+
。我相信以下机制起作用:
14.8.2.2 使用函数模板的地址推导模板参数 [temp.deduct.funcaddr]:
模板参数可以从获取重载函数地址时指定的类型推导出来(13.4)。功能模板的功能类型和指定的类型用作P和A的类型,扣除按照14.8.2.5中的描述进行。
因此,实际的模板推导将基于funct
的类型完成。我相信 14.8.2.5 的相关段落是 1 和 2 。
14.8.2.5 从类型[temp.deduct.type]中减去模板参数`:
1 模板参数可以在几个不同的上下文中推导出来,但在每种情况下,根据模板参数指定的类型(称为P)与实际类型进行比较(称为A并且,在替换推导出的值之后,尝试找到将产生P的模板参数值(类型参数的类型,非类型参数的值或模板参数的模板)(调用)它推导出A),与A兼容。
2 在某些情况下,扣除是使用一组P和A类型完成的,在其他情况下,会有一组相应的类型P和A.类型扣除是独立完成的对于每个P / A对,然后组合推导出的模板参数值。如果不能对任何P / A对进行类型推导,或者对于任何一对,推导导致一组以上可能的推导值,或者如果不同的对产生不同的推导值,或者任何模板参数仍未推断或明确推断特定的,模板 论证推论失败。
基本上,您将twice
作为指向operator+
的指针传递,然后通过operator+
中定义的函数类型推导出模板参数。因此,您的实际类型A
为int (*)(int in)
,P
的模板类型twice
与A
匹配且仅int twice(int)
适合。
我希望我把一切都搞定。