下面的代码编译(gcc 4.7.2 或 icc 13)并产生“1 2”输出。这意味着 const
预选赛被删除,我。即,f<int&>
具有参数类型 int&
.
为什么会这样?据我了解,根据 §14.3.1.4:
If a template-argument for a template-parameter
T
names a type “reference to cv1S
”, an attempt to create the type “reference to cv2T
” creates the type “reference to cv12S
”, where cv12 is the union of the cv-qualifiers cv1 and cv2. Redundant cv-qualifiers are ignored.
const
不应该被丢弃。这是代码:
#include <iostream>
using namespace std;
template <typename T>
void f(const T& t)
{
t++;
}
int main()
{
int a = 1;
cout << a;
f<int&>(a);
cout << ' ' << a << endl;
return 0;
}
最佳答案
当标志 -std=c++98
时,GCC 4.7.2 不编译它被指定。事实上,在 C++98(以及 C++03)中,对引用的引用不会崩溃。
尝试实例化 f<int&>
, 其中T = int&
, 生成以下函数签名(这里我有意切换参数类型 T
和 const
说明符的位置,这是允许的,因为 const T&
与 T const&
相同):
void f(int& const& t) // ERROR: reference to reference is illegal
以上在 C++98 和 C++03 中都是不合法的。一致地,这是您从 GCC 4.7.2 得到的错误:
Compilation finished with errors:
source.cpp: In function 'int main()':
source.cpp:15:14: error: no matching function for call to 'f(int&)'
source.cpp:15:14: note: candidate is:
source.cpp:5:6: note: template<class T> void f(const T&)
source.cpp:5:6: note: template argument deduction/substitution failed:
source.cpp: In substitution of 'template<class T> void f(const T&) [with T = int&]':
source.cpp:15:14: required from here
source.cpp:5:6: error: forming reference to reference type 'int&'
不过,如果您使用 -std=c++11
标志,然后编译器在实例化模板时执行引用折叠:对左值引用的左值引用成为左值引用:
void f(int& const& t) == void f(int& t)
这里是 const
限定符被删除,因为它适用于引用,而不适用于引用的对象。由于无法重新分配引用,因此它们是 const
本质上,这就是为什么 const
被认为是多余的并被删除。参见 this Q&A on SO 的解释。
这会产生一个对左值引用的左值引用,它解析为一个简单的左值引用。因此,右侧的签名被实例化。
以上是解决 f<int&>(a)
调用的可行候选方案因此,它编译没有错误。
关于C++98/03 引用折叠和 cv 限定符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14761581/