为什么const数组优先绑定到const T&parameters而不是T &&参数?

Kno*_*abe 5 c++ c++11

使用"T &&"参数重载函数模板通常是一个坏主意,因为它可以绑定到任何东西,但我们假设我们仍然这样做:

template<typename T>
void func(const T& param)
{
  std::cout << "const T&\n";
}

template<typename T>
void func(T&& param)
{
  std::cout << "T&&\n";
}
Run Code Online (Sandbox Code Playgroud)

我的理解是,const T&重载将被调用为const lvalues的参数,并且T&&将为所有其他参数类型调用重载.但是考虑一下当我们func使用const和非const内容的数组调用时会发生什么:

int main()
{
  int array[5] = {};
  const int constArray[5] = {};

  func(array);             // calls T&& overload
  func(constArray);        // calls const T& overload
}
Run Code Online (Sandbox Code Playgroud)

VC10,VC11和gcc 4.7同意显示的结果.我的问题是为什么第二个调用会调用const T&重载.简单的答案是它constArray有一个const,但我认为这太简单了.其推导的类型T(不论模板有选择的)是这样的类型"的5个常量整数数组" paramconst T&过载将是"参考的5个常量整数常量数组".但是名为constArray的数组本身并不是const.那么为什么调用不func(constArray)调用T&&重载,从而产生一个param"引用5个const整数数组"的类型?

这个问题的动机是与c ++模板函数参数演绎和函数解析中的问题相关的讨论,但我认为该线程在其他问题上有所偏差,并没有澄清我现在在这里问的问题.

eca*_*mur 7

在函数参数列表(以及其他任何地方)中,对数组类型的cv限定进行了右移以限定数组元素类型.例如,with T = int [5],const T &转换为int const (&) [5].

3.9.3 CV-quali firs [basic.type.quali fi er]

2 - [...]应用于数组类型的任何cv限定符都会影响数组元素类型,而不是数组类型(8.3.4).

所以func使用类型参数的int const [5]调用被推断为对以下任何一个的调用:

void func<int [5]>(int const (&) [5])
void func<int const (&) [5]>(int const (& &&) [5])
// where the above collapses to
// 'void func<int const (&) [5]>(int const (&) [5])'
Run Code Online (Sandbox Code Playgroud)

两种重载都是可行的,但前者是首选:

设T1为const T &模板,T2为T &&模板; 也就是说,它们的参数类型是T1:= const T &和T2:= T &&.然后,转换的参数类型(14.5.6.2:3)可以写成A1:= const C &,A2:= D &&用于合成类型C,D.

现在,我们尝试针对T2(14.8.2.4:2)对T1进行排序,首先使用A1作为参数模板,使用P2作为参数模板.我们除去给A1引用(14.8.2.4:5) - > const C和T2 - > T,然后取出CV-资格(14.8.2.4:7)给予A1 - > C和T2 - > T.模板T可以推导出C(14.8.2.4:8),因此A1至少与P2一样专业 ; 相反,A2 - > D- > D,P1 - > const T- > T,并且T可以推导出来D,因此A2至少与P1一样专业.

这通常意味着两者都不比另一个更专业; 但是,因为PA类型是引用类型14.8.2.4:9适用,并且因为A1是左值引用而P2不是,所以T1被认为比T2更专业.(引用类型之间的联系也可以通过同一条款下的cv-qualification来打破.)