简体   繁体   English

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

[英]How to determine programmatically if an expression is rvalue or lvalue in C++?

What's the best way to determine if an expression is a rvalue or lvalue in C++? 确定表达式是否是C ++中的右值或左值的最佳方法是什么? Probably, this is not useful in practice but since I am learning rvalues and lvalues I thought it would be nice to have a function is_lvalue which returns true if the expression passed in input is a lvalue and false otherwise. 可能这在实践中没有用,但由于我正在学习rvalues和lvalues,我认为有一个函数is_lvalue会很好,如果在输入中传递的表达式是左值,则返回true,否则返回false。

Example: 例:

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

Most of the work is already done for you by the stdlib, you just need a function wrapper: stdlib已经完成了大部分工作,你只需要一个函数包装器:

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

in the case you pass a std::string lvalue then T will deduce to std::string& or const std::string& , for rvalues it will deduce to std::string 在你传递std::string左值的情况下, T将推导为std::string&const std::string& ,对于rvalues,它将推导为std::string

Note that Yakk's answer will return a different type, which allows for more flexibility and you should read that answer and probably use it instead. 请注意, Yakk的答案将返回不同的类型,这样可以提供更大的灵活性,您应该阅读该答案,并可能使用它。

I solved the above question using two overloaded template functions. 我使用两个重载的模板函数解决了上述问题。 The first takes as input a reference to a lvalue and return true . 第一个接受对左值的引用作为输入并返回true Whereas the second function uses a reference to rvalue. 而第二个函数使用对rvalue的引用。 Then I let the compiler match the correct function depending on the expression passed as input. 然后我让编译器匹配正确的函数,具体取决于作为输入传递的表达式。

Code: 码:

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

Output: 输出:

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

I would take a page from boost::hana and make the return value of is_lvalue encode the lvalue-ness of its argument both as a constexpr value, and as a type. 我会采取从页面boost::hana ,使返回值is_lvalue编码它的参数作为的左值岬constexpr价值作为一个类型。

This lets you do stuff like tag dispatching without extra boilerplate. 这使您可以执行标记调度等操作,而无需额外的样板。

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

the body of this function does nothing, and the parameter's value is ignored. 此函数的主体不执行任何操作,并忽略参数的值。 This lets it be constexpr even on non-constexpr values. 这使它即使在非constexpr值上也可以是constexpr。

An advantage of this technique can be seen here: 这里可以看到这种技术的一个优点:

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 ) );

Not only is the return value of is_lvalue available in a constexpr context (as true_type and false_type have a constexpr operator bool ), but we can easily pick an overload based on its state. 不仅is_lvalue的返回值在constexpr上下文中可用(因为true_typefalse_type具有constexpr operator bool ),但我们可以根据其状态轻松选择重载。

Another advantage is that it makes it hard for the compiler to not inline the result. 另一个优点是它使编译器很难内联结果。 With a constexpr value, the compiler can 'easily' forget that it is a true constant; 使用constexpr值,编译器可以“轻松”忘记它是一个真正的常量; with a type, it has to be first converted to bool for the possibility of it being forgotten to happen. 一个类型,它必须首先转换为bool因为它可能被遗忘。

Use std::is_lvalue_reference and std::is_rvalue_reference . 使用std::is_lvalue_referencestd::is_rvalue_reference

You don't need a wrapper if you're happy with using decltype. 如果您对使用decltype感到满意,则不需要包装器。

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

In C++17 you'll be able to use the following: 在C ++ 17中,您将能够使用以下内容:

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

Or you could write a wrapper as @Ryan Haining suggests, just make sure you get the types correct. 或者你可以像@Ryan Haining建议的那样写一个包装器,只要确保你的类型正确。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM