4

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?

Mochan
  • 1,329
  • 1
  • 13
  • 27
  • 1
    May be a dup of: https://stackoverflow.com/questions/13725747/concise-explanation-of-reference-collapsing-rules-requested-1-a-a-2 – Eljay May 09 '19 at 17:05
  • 1
    Agree. This might not be the best dup, but it explains the reference collapsing rules. TL;DR: Ampersands do combine, but they form a lvalue-reference, not rvalue one. – HolyBlackCat May 09 '19 at 17:06
  • 1
    Personally I think that's better as a cross-reference than a dupe but whatever :) – Lightness Races in Orbit May 09 '19 at 17:29

1 Answers1

2

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:

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055