non-const reference of type from an rvalue

守給你的承諾、 提交于 2019-12-23 07:25:00

问题


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.


回答1:


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 &&>())) &&



回答2:


You could do this much simpler:

template<typename T>
auto foo(T &&t) -> decltype(std::get<0>(std::forward<T>(t))) {
    return std::get<0>(t);
}



回答3:


foo returns an rvalue reference so you can't bind it to an auto& because that requires an lvalue reference.

foo2 uses a "universal reference" that evaluates to an lvalue reference in this case because std::get returns an lvalue reference and you perfectly forward it to the return value.



来源:https://stackoverflow.com/questions/24082925/non-const-reference-of-type-from-an-rvalue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!