从右值参数推导对const的引用

deducing references to const from rvalue arguments

本文关键字:const 引用 值参 参数      更新时间:2023-10-16

好吧,这个问题可能看起来很傻,但它来了:

template <typename T>
void foo(T& x)
{
}
int main()
{
    foo(42);
    // error in passing argument 1 of 'void foo(T&) [with T = int]'
}

是什么阻止C++用T = const int实例化foo函数模板?

问题是模板类型推导必须计算出精确匹配,在这种特殊情况下,由于签名中的引用,精确匹配需要一个左值。值42不是左值,而是右值,并且用const int解析T不会产生完全匹配。由于模板类型的推导仅限于精确匹配,因此不允许进行该推导。

如果不是使用文字,而是使用不可变的左值,那么编译器将适当地推导类型,因为const int将成为参数的完美匹配:

const int k = 10;
foo( k );            // foo<const int>( const int & ) is a perfect match

现在有一个特殊的规则可以调用一个带有右值的常量引用(非可变左值)的函数,这意味着要创建一个稍后绑定到引用的临时左值,但要使该规则生效,函数必须先有签名,这就是为什么明确声明模板类型为const int有效的原因:foo<const int>(42)

这就是规则;-)。如果让编译器从参数中推导类型,它会选择最简单的方法。

在我看来,这并不是不合理的。你的模板说它需要一个非常量引用,所以它不使用右值编译。

您可以在调用站点告诉它您的意思:foo<int const>(42);,或者更改模板以明确它不需要可变引用:template <typename T> void foo(T const & x) { }

在C++11中,您可以有更多的选项来表达您的模板将接受和不接受的内容。

无论是模板函数还是普通函数,右值都不能通过引用传递。(所以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;这样的有效语句,它开始给出错误。这可能就是为什么编译器在第一阶段阻止自己的原因!