如何在C++中以编程方式确定表达式是否为rvalue或lvalue?

Giu*_*Pes 50 c++ rvalue lvalue c++11

确定表达式是否是C++中的右值或左值的最佳方法是什么?可能这在实践中没有用,但是因为我正在学习rvalues和lvalues,所以我认为is_lvalue如果在输入中传递的表达式是左值而其他函数返回true 会更好.

例:

std::string a("Hello");
is_lvalue(std::string()); // false
is_lvalue(a); // true  
Run Code Online (Sandbox Code Playgroud)

Rya*_*ing 61

stdlib已经完成了大部分工作,你只需要一个函数包装器:

template <typename T>
constexpr bool is_lvalue(T&&) {
  return std::is_lvalue_reference<T>{};
}
Run Code Online (Sandbox Code Playgroud)

如果你传递一个std::string左值,那么将推T导出std::string&或者const std::string&,对于它将推导出的右值std::string

请注意,Yakk的答案将返回不同的类型,这样可以提供更大的灵活性,您应该阅读该答案,并可能使用它.


Giu*_*Pes 26

我使用两个重载的模板函数解决了上述问题.第一个接受对左值的引用并返回true.而第二个函数使用对rvalue的引用.然后我让编译器匹配正确的函数,具体取决于作为输入传递的表达式.

码:

#include <iostream>

template <typename T>
constexpr bool is_lvalue(T&) {
    return true;
}

template <typename T>
constexpr bool is_lvalue(T&&) {
    return false;
}

int main()
{
    std::string a = std::string("Hello");
    std::cout << "Is lValue ? " << '\n';
    std::cout << "std::string() : " << is_lvalue(std::string()) << '\n';
    std::cout << "a : " << is_lvalue(a) << '\n';
    std::cout << "a+b : " << is_lvalue(a+ std::string(" world!!! ")) << '\n';
} 
Run Code Online (Sandbox Code Playgroud)

输出:

Is Lvalue ? 
std::string() : 0
a : 1
a+b : 0
Run Code Online (Sandbox Code Playgroud)

  • 由于参数未使用,因此您应将这两个函数标记为`constexpr`,因为类型在编译时始终是已知的 (7认同)
  • 我,我会更加确定地返回`std :: true_type`和`false_type`. (4认同)
  • @GiuseppePes它将结果的编译时间移动到类型系统中,这使您可以执行将其传递给模板函数并确实传播其值的操作.同时,true类型有一个constexpr运算符bool,因此它也可以在该上下文中使用. (3认同)
  • @Yakk在这种情况下使用`std :: true_type`有什么好处? (2认同)

Yak*_*ont 16

我会采取从页面boost::hana并返回值is_lvalue编码它的参数的左值的烦躁constexpr值,作为一个类型.

这使您可以执行标记调度等操作,而无需额外的样板.

template<class T>
constexpr std::is_lvalue_reference<T&&>
is_lvalue(T&&){return {};}
Run Code Online (Sandbox Code Playgroud)

此函数的主体不执行任何操作,并忽略参数的值.这使它即使在非constexpr值上也可以是constexpr.

这里可以看到这种技术的一个优点:

void tag_dispatch( std::true_type ) {
  std::cout << "true_type!\n";
}
void tag_dispatch( std::false_type ) {
  std::cout << "not true, not true, shame on you\n";
}

tag_dispatch( is_lvalue( 3 ) );
Run Code Online (Sandbox Code Playgroud)

不仅is_lvalueconstexpr上下文中可用的返回值(具有true_typefalse_type可用constexpr operator bool),但我们可以根据其状态轻松选择重载.

另一个优点是它使编译器很难内联结果.使用constexpr值,编译器可以"轻松"忘记它是一个真正的常量; 对于一种类型,它必须首先转换bool为它被遗忘的可能性.

  • @Yakk这是C++.我们*在这里只是略微好一点. (4认同)
  • @RyanHaining更好的错误信息?`is_lvalue_reference <Foo &&>`似乎比`is_lvalue_reference <Foo>`更清晰,在重载决议失败时对我来说会更清楚. (2认同)

Pha*_*rap 8

使用std::is_lvalue_referencestd::is_rvalue_reference.

如果您对使用decltype感到满意,则不需要包装器.

std::string a("Hello");
std::is_lvalue_reference<decltype((std::string()))>::value; // false
std::is_lvalue_reference<decltype((a))>::value; // true
Run Code Online (Sandbox Code Playgroud)

在C++ 17中,您将能够使用以下内容:

std::string a("Hello");
std::is_lvalue_reference_v<decltype((std::string()))>; // false
std::is_lvalue_reference_v<decltype((a))>; // true
Run Code Online (Sandbox Code Playgroud)

或者你可以像@Ryan Haining建议的那样写一个包装器,只要确保你的类型正确.