来自右值类型的非const引用

non-const reference of type from an rvalue

本文关键字:const 引用 类型      更新时间:2023-10-16

考虑以下代码:

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

当我试图编译这个时,我得到了以下错误:

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}'

好吧,那就好了,但是:

  • 首先,这个Widget w不是临时的。为什么它把它当作暂时的?

  • 在第二,为什么foo2工作比?

注:正如你所看到的,我试着写一个函数,它同时操作左值和右值。如果第一个元素是临时的,我想返回右值,如果不是-左值

tuple_element返回元素类型,而不是引用类型(除非元素类型本身是引用类型)。

如果类型T是引用类型,则需要让它返回引用类型。

这可以用条件来表示:

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

或者,更容易,使用decltype,因为std::get已经为您执行此计算:

decltype(std::get<0>(std::declval<T &&>())) &&

你可以做得更简单:

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

foo返回一个右值引用,所以你不能将它绑定到auto&,因为这需要一个左值引用。

foo2使用"通用引用",在这种情况下计算为左值引用,因为std::get返回左值引用,并且您完美地将其转发到返回值。