简体   繁体   中英

C++98/03 reference collapsing and cv qualifiers

The code below compiles (gcc 4.7.2 or icc 13) and produces "1 2" output. Which means that const qualifier is dropped, ie, 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 cv1 S ”, an attempt to create the type “reference to cv2 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.

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

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM