Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

non-const reference of type from an rvalue

Consider the following code:

class Widget{};

template<typename T>
T &&foo2(T &&t){
    return std::forward<T>( t );
}

/// Return 1st element
template<typename T>
typename std::tuple_element<0, typename std::decay<T>::type >::type  &&foo(T &&t){
    return std::forward< typename std::tuple_element<0, typename std::decay<T>::type >::type >
            ( std::get<0>(t) );
}

Widget w;
auto list = std::make_tuple(
    w,
    Widget()
);


int main()
{
  auto &l  = foo(list );                      // This is NOT work
  //auto &l2 = foo2( std::get<0>(list) );     // This one works.
}

http://coliru.stacked-crooked.com/a/4d3b74ca6f043e45

When I tried to compile this I got the following error:

error: invalid initialization of non-const reference of type 'Widget&' from an rvalue of type 'std::tuple_element<0ul, std::tuple<Widget, Widget> >::type {aka Widget}'

Well, and that would be ok, but:

  • at first, that Widget w is not temporary. Why it treat it like temporary?

  • at second, why foo2 works than?

P.S. As you see, I try to write function which operates both with lvalue and rvalue. If first element is temporary I want to return rvalue, if it is not - lvalue.

like image 391
tower120 Avatar asked Jun 06 '14 13:06

tower120


1 Answers

tuple_element returns the element type, not a reference type (unless the element type is itself a reference type).

You need to have it return a reference type if the type T is a reference type.

This can be expressed with a conditional:

typename std::conditional<std::is_lvalue_reference<T>::value,
    typename std::add_lvalue_reference<
        typename std::tuple_element<0, typename std::decay<T>::type >::type>::type,
    typename std::tuple_element<0, typename std::decay<T>::type >::type>::type

Or, more easily, using decltype, since std::get already performs this calculation for you:

decltype(std::get<0>(std::declval<T &&>())) &&
like image 163
ecatmur Avatar answered Sep 28 '22 05:09

ecatmur