Why is the output of `typeid(T&).name()` given as `T` instead of `T&`?

475 views Asked by At

As the subject, you could check the related code on https://godbolt.org/z/qtjVP6.

For your convience, the code is posted below:

#include<typeinfo>
#include<iostream>

class Widget{};

Widget someWidget;

int main()
{
    Widget&& var1 = Widget{};      // here, “&&” means rvalue reference
    auto&& var2 = var1;              // here, “&&” does not mean rvalue reference

    std::cout << typeid(var2).name() << std::endl;
}

Output:6Widget

echo 6Widget | c++filt -t says Widget.

I would be grateful to have some help on this question.

2

There are 2 answers

3
iBug On BEST ANSWER

Per C++ Reference (emphasis mine):

1) Refers to a std::type_info object representing the type type. If type is a reference type, the result refers to a std::type_info object representing the referenced type.

So for type = T&, typeid(type) will give results about T (reference removed).

It's easy to understand IMO, as for all purposes, a variable of type T& is functionally equivalent to one of type T.

2
Cheshar On

Although, the answer given by iBug is correct in a way, it doesn't really apply to your case.

Let's look at what C++ standard has to say about this. We can see [expr]p5 says:

5 If an expression initially has the type “reference to T” ([dcl.ref], [dcl.init.ref]), the type is adjusted to T prior to any further analysis. The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression.

All this is saying is that in:

     std::cout << typeid(var2).name() << std::endl;

the type of var2 is adjusted from Widget& to Widget before the expression is further evaluated. Now it's easier to see why typeid(var2).name() returns a string corresponding to type Widget.


In case, you want to dig deeper, [expr.typeid]p3 says:

3 When typeid is applied to an expression other than a glvalue of a polymorphic class type, the result refers to a std::type_info object representing the static type of the expression. Lvalue-to-rvalue (4.1), array-topointer (4.2), and function-to-pointer (4.3) conversions are not applied to the expression. If the type of the expression is a class type, the class shall be completely-defined. The expression is an unevaluated operand (Clause 5).

Which basically means that var2 in typeid(var2) is a glvalue of a non-polymorphic class type and that for an expression of such a type, the type is its static type. The type therefore is Widget.


See this for more details.