Lingxi
Lingxi

Reputation: 14987

Confusion about the return type of std::get() on std::tuple objects

Please see the following code (see it live here):

#include <iostream>
#include <tuple>
#include <type_traits>
#include <utility>

struct S {
  int&& v;  
};

int main() {
  std::tuple<int&&> t(1);
  std::cout << std::is_same<int, decltype(std::get<0>(t))>{} << std::endl;
  std::cout << std::is_same<int&, decltype(std::get<0>(t))>{} << std::endl;
  std::cout << std::is_same<int&&, decltype(std::get<0>(t))>{} << std::endl;
  S s{1};
  std::cout << std::is_same<int&&, decltype(s.v)>{} << std::endl;
}

I'm expecting to see the output 0 0 1 1, but both GCC and clang give the output 0 1 0 1 instead. Really confused. Could someone give me an explanation?

Upvotes: 2

Views: 624

Answers (2)

TartanLlama
TartanLlama

Reputation: 65770

The relevant std::get overloads are these:

template< std::size_t I, class... Types >
typename std::tuple_element<I, tuple<Types...> >::type&
get( tuple<Types...>& t );

template< std::size_t I, class... Types >
typename std::tuple_element<I, tuple<Types...> >::type&&
get( tuple<Types...>&& t );

Note that an lvalue reference is returned if the argument is an lvalue, and an rvalue reference is returned if the argument is an rvalue. t is an lvalue, so an lvalue is returned.

Upvotes: 1

Jarod42
Jarod42

Reputation: 218323

Look at signature of std::get:

template< std::size_t I, class... Types >
constexpr std::tuple_element_t<I, tuple<Types...> >&
    get( tuple<Types...>& t )

template< std::size_t I, class... Types >
constexpr std::tuple_element_t<I, tuple<Types...> >&&
    get( tuple<Types...>&& t )

In your case t is a l-value, so it return int&& & which became int&.

Upvotes: 3

Related Questions