#include <iostream>
#include <typeinfo>
class A {};
A f() { return A(); }
int main() {
auto &&a = f();
std::cout << typeid(f()).name() << std::endl;
std::cout << typeid(a).name() << std::endl;
std::cout << typeid(A{}).name() << std::endl;
return 0;
}
It outputs
1A
1A
1A
Questions are,
1A
mean here? (GCC on a linux box)auto &&
should be a forwarding reference, and in this case since f()
returns an A
object by value, a
should be deduced to rvalue reference, correct?a
is indeed rvalue reference, and since a (temporary) rvalue's lifetime could only be extended by a const lvalue ref, a
should go out of scope right after this line, is that correct?Edit: Fixed the most vexing problem in the last cout
statement, as many pointed out.
Summary of the great answers, for posterity:
1A
is internal representation of type A
, by Guillaume Racicot. And F1AvE
indicates a Function style cast in typeid(A()) resulting in a prvalue, by Ted Lyngmo.typeid()
is not the tool to check reference, as it gives the referenced end type. Ted Lyngmo gave the right way to do it, and yes it is an r-value reference.static_assert(std::is_rvalue_reference_v<decltype(a)>); // like this, ...
static_assert(std::is_same_v<decltype(a), A&&>); // or like this
what does
1A
mean here? (GCC on a linux box)
It means that the length of the name is 1
followed by the letter. There are many rules on how to mangle a type, but it encodes its namespace, template parameter value and other things.
auto &&
should be a forwarding reference, and in this case since f() returns an A object by value, a should be deduced to rvalue reference, correct?
The typeid
operator discards all top level cv and ref qualifiers.
Also, it see through references and returns the type info for the refered type instead.
From the typeid operator page:
If type is a reference type, the result refers to a std::type_info object representing the referenced type.
But yes, the type deduced is A
, so you are declaring A&&
. But even if a
is an rvalue reference, the expression a
is an lvalue.
If a is indeed rvalue reference, and since a (temporary) rvalue's lifetime could only be extended by a const lvalue ref, a should go out of scope right after this line, is that correct?
The lifetime end at the end of the scope, per the lifetime extension rules.
Now for why the typeid is different.
This is not about rvalue or forwarding references. This is the most vexing parse problem. A()
is a function that returns A
and has no parameters.
Use {}
for initialization and you'll see the problem disappear:
#include <iostream>
#include <typeinfo>
class A {};
A f() { return A(); }
int main() {
auto &&a = f();
std::cout << typeid(f()).name() << std::endl; // 1A
std::cout << typeid(a).name() << std::endl; // 1A
std::cout << typeid(A{}).name() << std::endl; // 1A
return 0;
}