c++templatesreference-typereference-collapsing

What is the type of a reference of a reference in a template class


In the code below, what are the types of a and b?

template <class T = const int&>
struct A
{
    T& a;
    T b;
};

int main() {
    int i = 1;
    A<> a{i, i};
    return 1;
}

I used the code from this post that can give the type of a variable. -> post

But, it says both types are i const&.

int main() {
    int i = 1;
    A<> a{i, i};

    std::cout << type_name<decltype(a.a)>() << std::endl;
    std::cout << type_name<decltype(a.b)>() << std::endl;

    return 0;
}

Are T& and T be the same type in the above case?

Do those ampersands combine and become r-value or some other rule?


Solution

  • T is const int& because that's what you told it to be.

    T& is also const int& because reference collapsing transforms your T& into T:

    [dcl.ref]/6: If a typedef-name ([dcl.typedef], [temp.param]) or a decltype-specifier ([dcl.type.simple]) denotes a type TR that is a reference to a type T, an attempt to create the type “lvalue reference to cv TR” creates the type “lvalue reference to T”, while an attempt to create the type “rvalue reference to cv TR” creates the type TR. [ Note: This rule is known as reference collapsing. — end note ] [ Example:

    int i;
    typedef int& LRI;
    typedef int&& RRI;
    
    LRI& r1 = i;                    // r1 has the type int&
    const LRI& r2 = i;              // r2 has the type int&
    const LRI&& r3 = i;             // r3 has the type int&
    
    RRI& r4 = i;                    // r4 has the type int&
    RRI&& r5 = 5;                   // r5 has the type int&&
    
    decltype(r2)& r6 = i;           // r6 has the type int&
    decltype(r2)&& r7 = i;          // r7 has the type int&
    

    — end example ]

    This is for convenience, because there is no such thing as const int& & (reference to reference; not to be confused with rvalue reference type const int&& which does exist!) and it's handy to be able to just write code like yours without having to manually "get rid of" the "extra" &.

    The rationale behind this rule is explained in more detail here: