6

下面的代码编译(gcc 4.7.2 或 icc 13)并产生“1 2”输出。这意味着const限定符被删除,即f<int&>具有参数类型int&

为什么会这样?据我了解,根据§14.3.1.4:

如果模板参数的模板参数T将类型命名为“对cv1 S的引用”,则尝试创建类型“对cv2 T的引用”会创建类型“对cv12 S的引用”,其中cv12是 cv 限定符cv1的并集和cv2。冗余的 cv 限定符被忽略。

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;
}
4

2 回答 2

5

这是 1770 年,有问题的引用似乎起源于:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1770.html

14.3.1 - 模板类型参数

-4- 如果模板参数 T 的模板参数将类型命名为“lvalue-reference to cv1 S”,则尝试创建类型“(lvalue or rvalue) reference to cv2 T”会创建类型“lvalue-reference到 cv12 S”,其中 cv12 是 cv 限定符 cv1 和 cv2 的并集。如果模板参数将类型命名为“对 cv1 S 的右值引用”,则尝试创建类型“对 cv2 T 的左值引用”会创建类型“对 cv12 S 的左值引用”。如果模板参数将类型命名为“对 cv1 S 的右值引用”,则尝试创建类型“对 cv2 T 的右值引用”会创建类型“对 cv12 S 的右值引用”。冗余的 cv 限定符被忽略。

这是 2118 的报价已被删除的地方:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html

14.3.1 - 模板类型参数

-4- 如果模板参数 T 的模板参数将类型“对 cv1 S的引用”命名为对类型 A 的引用,则尝试创建类型“对 cv2 T的引用”“对 cv 的左值引用” T”创建类型“对 cv12 S 的引用”,其中 cv12 是 cv 限定符 cv1 和 cv2 的并集。冗余 cv 限定符被忽略“对 A 的左值引用”,而尝试创建类型“对 cv T 的右值引用”会创建类型 T。

您引用的内容似乎是过时的措辞。

于 2013-02-07T21:59:05.533 回答
5

指定标志时,GCC 4.7.2 不会编译-std=c++98它。事实上,在 C++98(以及 C++03)中,对引用的引用不会崩溃。

尝试实例化f<int&>, whereT = 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认为是多余的和删除的。有关解释,请参阅关于 SO 的此问答

这会产生一个对左值引用的左值引用,它解析为一个简单的左值引用。因此,右侧的签名被实例化。

以上是解决调用的可行候选者f<int&>(a),因此它编译时没有错误。

于 2013-02-07T21:56:20.490 回答