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

时间:2016-03-29 22:43:25

标签: c++ c++11 lvalue rvalue

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

示例:

std::string a("Hello");
is_lvalue(std::string()); // false
is_lvalue(a); // true  

4 个答案:

答案 0 :(得分:58)

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

template <typename T>
constexpr bool is_lvalue(T&&) {
  return std::is_lvalue_reference<T>{};
}

如果您传递std::string左值,则T将推断为std::string&const std::string&,对于rvalues,它将推导为std::string

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

答案 1 :(得分:25)

我使用两个重载的模板函数解决了上述问题。第一个接受对左值的引用并返回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';
} 

输出:

Is Lvalue ? 
std::string() : 0
a : 1
a+b : 0

答案 2 :(得分:15)

我会从boost::hana获取一个页面,并使is_lvalue的返回值将其参数的左值编码为constexpr值, 作为一种类型。

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

template<class T>
constexpr std::is_lvalue_reference<T&&>
is_lvalue(T&&){return {};}

此函数的主体不执行任何操作,并忽略参数的值。这使它即使在非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 ) );

is_lvalue上下文中constexpr的返回值不仅可用(true_typefalse_typeconstexpr operator bool),但我们可以轻松根据其状态选择一个过载。

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

答案 3 :(得分:7)

使用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

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

std::string a("Hello");
std::is_lvalue_reference_v<decltype((std::string()))>; // false
std::is_lvalue_reference_v<decltype((a))>; // true

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