使用“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";
}
我的理解是,const T&
重载将被调用为const lvalues的参数,并且将为所有其他参数类型调用T&&
重载。但是考虑当我们使用const和非const内容数组调用func
时会发生什么:
int main()
{
int array[5] = {};
const int constArray[5] = {};
func(array); // calls T&& overload
func(constArray); // calls const T& overload
}
VC10,VC11和gcc 4.7同意显示的结果。我的问题是为什么第二个调用会调用const T&
重载。简单的答案是constArray
中有一个const,但我认为这太简单了。推导出的类型T(无论选择何种模板)都是“5个const整数的数组”,因此param
重载中const T&
的类型将是“对5个const整数的const数组的引用” 。但是名为constArray的数组本身并不是const。那么为什么调用func(constArray)
不会调用T&&
重载,从而产生param
“引用5个const整数数组”的类型?
这个问题是由与c++ template function argument deduce and function resolution问题相关的讨论推动的,但我认为这个问题在其他问题上存在偏见,并没有澄清我现在在这里提出的问题。
答案 0 :(得分:7)
在函数参数列表(以及其他任何地方)中,对数组类型的cv限定进行了右移以限定数组元素类型。例如,对于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])'
两种重载都是可行的,但前者是首选:
设T1为const T &
模板,T2为T &&
模板;也就是说,它们的参数类型是T1:= const T &
和T2:= T &&
。然后,对于合成类型const C &
,D &&
,转换后的参数类型(14.5.6.2:3)可以写成A1:= C
,A2:= D
。
现在,我们尝试针对T2(14.8.2.4:2)对T1进行排序,首先使用A1作为参数模板,使用P2作为参数模板。我们删除了引用A1 - &gt;的引用(14.8.2.4:5)。 const C
和T2 - &gt; T
,然后删除cv-qualification(14.8.2.4:7),给出A1 - &gt; C
和T2 - &gt; T
。模板T
可以推导为C
(14.8.2.4:8),因此 A1至少与P2 一样专业;相反,A2 - > D
- &gt; D
,P1 - &gt; const T
- &gt; T
和T
可以推断为D
,因此 A2至少与P1 一样专业。
这通常意味着两者都不比另一个更专业;但是,因为P
和A
类型是引用类型14.8.2.4:9适用,并且因为A1是左值引用而P2不是,所以T1被认为比T2更专业。 (引用类型之间的联系也可以通过同一条款下的cv-qualification来打破。)
答案 1 :(得分:3)
您混淆右值引用(如int&&
)和通用引用(由模板参数构成,如template <typename T> ... T&&
中)。
Rvalue引用确实不会绑定到左值。但是通用引用绑定到任何东西。问题是谁更合适。
您拥有的类型是int const [5]
。现在让我们看看:
针对T const &
:与T = int[5]
匹配。
针对T &&
:与T = int const (&)[5]
匹配。
前者是更好的匹配,在以下意义上:两个模板都产生相同的重载。但T = int[5]
比T = int const (&)[5]
更专业。您可以看到这一点,因为T = int const (&)[5]
可以通过T = U const &
实现为U = int[5]
。
请注意,要将左值绑定到通用引用,必须将类型本身推断为引用类型。
(显然array
与const T &
不匹配,因为它不是常量。它只能匹配T&&
,推断T = int (&)[5]
)。