问题
The code below compiles (gcc 4.7.2 or icc 13) and produces "1 2" output. Which means that const
qualifier is dropped, i. e., f<int&>
has the parameter type int&
.
Why does it happen? As I understand, according to §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
should not be dropped. Here is the code:
#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;
}
回答1:
GCC 4.7.2 does not compile this when the flag -std=c++98
is specified. In fact, in C++98 (as well as in C++03) references to references do not collapse.
An attempt to instantiate f<int&>
, where T = int&
, produces the following function signature (here I intentionally switch the position of the argument type T
and the const
specifier, which is allowed because const T&
is the same as T const&
):
void f(int& const& t) // ERROR: reference to reference is illegal
The above is not legal in C++98, nor in C++03. Consistently, this is the error you get from 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&'
Nevertheless, if you use the -std=c++11
flag, then the compiler performs reference collapsing when instantiating the template: an lvalue reference to an lvalue reference becomes an lvalue reference:
void f(int& const& t) == void f(int& t)
Here the const
qualifier gets dropped, because it applies to the reference, and not to the referenced object. Since references cannot be reassigned, they are const
by nature, which is why the const
is considered superfluous and removed. See this Q&A on SO for an explanation.
That yields an lvalue reference to an lvalue reference, which resolves into a simple lvalue reference. Hence, the signature on the right side is instantiated.
The above is a viable candidate to resolve the call for f<int&>(a)
and, therefore, it compiles without errors.
回答2:
Here is 1770 where the quote in question seems to originate:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1770.html
14.3.1 - Template type arguments
-4- If a template-argument for a template-parameter T names a type "lvalue-reference to cv1 S," an attempt to create the type "(lvalue or rvalue) reference to cv2 T" creates the type "lvalue-reference to cv12 S," where cv12 is the union of the cv-qualifiers cv1 and cv2. If the template-argument names a type "rvalue-reference to cv1 S," an attempt to create the type "lvalue-reference to cv2 T" creates the type "lvalue-reference to cv12 S." If the template-argument names a type "rvalue-reference to cv1 S," an attempt to create the type "rvalue-reference to cv2 T" creates the type "rvalue-reference to cv12 S." Redundant cv-qualifiers are ignored.
Here is 2118 where the quote has been struck out:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html
14.3.1 - Template type arguments
-4- If a template-argument for a template-parameter T names a type
"reference to cv1 S"that is a reference to a type A, an attempt to create the type"reference to cv2 T""lvalue-reference to cv T" creates the type"reference to cv12 S", where cv12 is the union of the cv-qualifiers cv1 and cv2. Redundant cv-qualifiers are ignored"lvalue-reference to A", while an attempt to create the type "rvalue-reference to cv T" creates the type T.
What you are quoting seems to be obsolete wording.
来源:https://stackoverflow.com/questions/14761581/c98-03-reference-collapsing-and-cv-qualifiers