Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::is_same returns false when comparing std::tuple_element and decltype(std::get)

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" );
like image 791
bremen_matt Avatar asked May 16 '19 09:05

bremen_matt


Video Answer


1 Answers

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 yields T&;
c) if the value category of expression is prvalue, then decltype yields T.

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 a std::type_info object representing the referenced type.

That means typeid(float&&) == typeid(float) is always true.

like image 158
songyuanyao Avatar answered Oct 19 '22 22:10

songyuanyao