问题
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