I can't find a similar question...
I think there are two "easy" ways of getting the type of the I^th element of a tuple at compile time (correct me if I am wrong):
using TI1 = typename std::tuple_element<I, Tuple>::type;
using TI2 = decltype(std::get<I>(Tuple{}));
In fact, if we print the types of each of these via typeid(...).name()
, these return the same value.
However... std::is_same
returns false when I compare these:
live example
Is this expected? why?
using Tuple = std::tuple<float,double>;
constexpr size_t I = 0;
static_assert(std::is_same<typename std::tuple_element<I, Tuple>::type,
decltype(std::get<I>(Tuple{}))>::value, "different types" );
std::get(std::tuple)
returns reference; that means using decltype
on it you'll get a reference type.
a) if the value category of expression is xvalue, then decltype yields
T&&
;
b) if the value category of expression is lvalue, then decltype yieldsT&
;
c) if the value category of expression is prvalue, then decltype yieldsT
.
For this case, the return type of std::get<I>(Tuple{})
is an rvalue-reference, then std::get<I>(Tuple{})
is an xvalue expression,
a function call or an overloaded operator expression, whose return type is rvalue reference to object, such as
std::move(x)
;
then decltype(std::get<I>(Tuple{}))
will be T&&
, i.e. float&&
; which is different with typename std::tuple_element<I, Tuple>::type
(i.e. float
).
Using std::remove_reference
you could get what you want. e.g.
static_assert(std::is_same<typename std::tuple_element<I, Tuple>::type,
std::remove_reference_t<decltype(std::get<I>(Tuple{}))>>::value, "different types" );
LIVE
And about why typeid
gives the same result,
(emphasis mine)
1) Refers to a
std::type_info
object representing the type type. If type is a reference type, the result refers to astd::type_info
object representing the referenced type.
That means typeid(float&&) == typeid(float)
is always true
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With