This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115e. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2024-11-11
[Voted into the WP at the October, 2006 meeting as part of paper J16/06-0188 = WG21 N2118.]
The resolution of issue 106 specifies that an attempt to create a type “reference to cv1 T,” where T is a typedef or template parameter of the type “reference to cv2 S,” actually creates the type “reference to cv12 S,” where cv12 is the union of the two sets of cv-qualifiers.
One objection that has been raised to this resolution is that it is inconsistent with the treatment of cv-qualification and references specified in 9.3.4.3 [dcl.ref] paragraph 1, which says that cv-qualifiers applied to a typedef or template argument that is a reference type are ignored. For example:
typedef int& intref; const intref r1; // reference to int const intref& r2; // reference to const int
In fact, however, these two declarations are quite different. In the declaration of r1, const applies to a “top-level” reference, while in the declaration of t2, it occurs under a reference. In general, cv-qualifiers that appear under a reference are preserved, even if the type appears in a context in which top-level cv-qualification is removed, for example, in determining the type of a function from parameter types (9.3.4.6 [dcl.fct] paragraph 3) and in template argument deduction (13.10.3.2 [temp.deduct.call] paragraph 2).
Another objection to the resolution is that type composition gives different results in a single declaration than it does when separated into two declarations. For example:
template <class T> struct X { typedef T const T_const; typedef T_const& type1; typedef T const& type2; }; X<int&>::type1 t1; // int& X<int&>::type2 t2; // int const&
The initial motivation for the propagation of cv-qualification during reference-to-reference collapse was to prevent inadvertent loss of cv-qualifiers in contexts in which it could make a difference. For example, if the resolution were changed to discard, rather than propagate, embedded cv-qualification, overload resolution could surprisingly select a non-const version of a member function:
struct X { void g(); void g() const; }; template <typename T> struct S { static void f(const T& t) { t.g(); // const or non-const??? } }; X x; void q() { S<X>::f(x); // calls X::g() const S<X&>::f(x); // calls X::g() }
Another potentially-surprising outcome of dropping embedded cv-qualifiers would be:
template <typename T> struct A { void f(T&); // mutating version void f(const T&); // non-mutating version }; A<int&> ai; // Ill-formed: A<int&> declares f(int&) twice
On the other hand, those who would like to see the resolution changed to discard embedded cv-qualifiers observe that these examples are too simple to be representative of real-world code. In general, it is unrealistic to expect that a template written with non-reference type parameters in mind will automatically work correctly with reference type parameters as a result of applying the issue 106 resolution. Instead, template metaprogramming allows the template author to choose explicitly whether cv-qualifiers are propagated or dropped, according to the intended use of the template, and it is more important to respect the reasonable intuition that a declaration involving a template parameter will not change the type that the parameter represents.
As a sample of real-world code, tr1::tuple was examined. In both cases — the current resolution of issue 106 and one in which embedded cv-qualifiers were dropped — some metaprogramming was required to implement the intended interface, although the version reflecting the revised resolution was somewhat simpler.
Notes from the October, 2005 meeting:
The consensus of the CWG was that the resolution of issue 106 should be revised not to propagate embedded cv-qualification.
Note (February, 2006):
The wording included in the rvalue-reference paper, J16/06-0022 = WG21 N1952, incorporates changes intended to implement the October, 2005 consensus of the CWG.