好吧,这看起来似乎是一个愚蠢的问题,但在这里:
template <typename T>
void foo(T& x)
{
}
int main()
{
foo(42);
// error in passing argument 1 of 'void foo(T&) [with T = int]'
}
什么阻止C ++使用foo
实例化T = const int
功能模板?
答案 0 :(得分:8)
问题是模板类型推导必须计算完全匹配,并且在特定情况下,由于签名中的引用,完全匹配需要左值。值42不是左值,而是右值,使用T
解析const int
不会产生完美匹配。由于模板类型扣除仅限于完全匹配,因此不允许扣除。
如果不是使用文字而是使用非可变左值,那么编译器将推导出适当的类型,因为const int
将成为参数的完美匹配:
const int k = 10;
foo( k ); // foo<const int>( const int & ) is a perfect match
现在有一个特殊的规则可以调用一个带有r值的const引用(不可变的左值)的函数,这意味着创建一个临时的左值,后来绑定到引用,但是该规则可以启动函数必须具有该签名,这就是明确说明模板的类型为const int
的原因:foo<const int>(42)
。
答案 1 :(得分:1)
他们的规则;-)。如果你让编译器从参数中推断出类型,它会选择最简单的东西。
这对我来说似乎并不合理。你的模板说它需要一个非const引用,所以它不能用rvalue编译。
您可以在通话网站上告诉它您的意思:foo<int const>(42);
或更改您的模板以明确它不需要可变引用:template <typename T> void foo(T const & x) { }
。
在C ++ 11中,您有更多选项来表达您的模板将会接受和不接受的内容。
答案 2 :(得分:0)
无论是模板还是普通函数, rvalue都不能通过引用传递。 (所以const T&
有效,但不是T&
)。
What is preventing C++ to instantiate the foo function template with T = const int instead?
假设,C ++允许并生成T = const int
。
现在有一段时间后你改变了foo,
template<typename T>
void foo (T& x)
{
x = 0;
}
现在编译器必须生成错误。对于最终用户来说,体验会很奇怪,就像x = 0;
之类的有效语句一样,它开始给出错误。这可能是编译器在第一阶段本身阻止的原因!