C模板函数中的左值和右值

我从http://www.cplusplus.com/reference/utility/forward取样:

// forward example
#include <utility>      // std::forward
#include <iostream>     // std::cout

// function with lvalue and rvalue reference overloads:
void overloaded (const int& x) {std::cout << "[lvalue]";}
void overloaded (int&& x) {std::cout << "[rvalue]";}

// function template taking rvalue reference to deduced type:
template <class T> void fn (T&& x) {
    overloaded (x);                   // always an lvalue
    overloaded (std::forward<T>(x));  // rvalue if argument is rvalue
}

int main () {
    int a;

    std::cout << "calling fn with lvalue: ";
    fn (a);
    std::cout << '\n';

    std::cout << "calling fn with rvalue: ";
    fn (0);
    std::cout << '\n';

    return 0;
}

打印

calling fn with lvalue: [lvalue][lvalue]
calling fn with rvalue: [lvalue][rvalue]

但是,如果我想制作重载模板,那样:

template<typename T>
void overloaded (const T& x) {std::cout << "[lvalue]";}
template<typename T>
void overloaded (T&& x) {std::cout << "[rvalue]";}

它打印

calling fn with lvalue: [rvalue][rvalue]
calling fn with rvalue: [rvalue][rvalue]

有没有办法使用模板功能来推断我转移到哪个对象的功能?

最佳答案
是的,可以,只需在第二个重载中添加一个const:

template<typename T>
void overloaded (const T& x);
template<typename T>
void overloaded (const T&& x);
//               ^^^^^

你需要const的原因是使x不是转发引用.转发引用非常贪婪,如果你没有传入完全相同的类型(包括任何cv限定符),那么将选择转发引用重载.

在您的情况下,因为您没有将const对象传递给重载,所以第二个重载将始终是更好的匹配.

但是如果你在那里添加一个const,那么它不再是转发引用,只能接受rvalues而不能接受左值,并且不会更好地匹配左值作为结果但是对于任何rvalues都比const& amp更好地匹配;超载.

如果您需要从x移动,那么您将不得不做其他事情.删除const&转发引用中的重载和分支,无论您是否具有右值或左值:

template <typename T> void overloaded(T &&x) {
  if /*constexpr*/ (std::is_lvalue_reference_v<T>)
    std::cout << "[lvalue]";
  else
    std::cout << "[rvalue]";
}

注意:如果您执行的某些特定内容对分支或其他分支无效,则需要使用constexpr.

转载注明原文:C模板函数中的左值和右值 - 代码日志