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

▼魔方 西西 提交于 2019-11-27 20:26:38

问题


What's the best way to determine if an expression is a rvalue or lvalue in 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.

Example:

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

回答1:


Most of the work is already done for you by the stdlib, you just need a function wrapper:

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

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.




回答2:


I solved the above question using two overloaded template functions. The first takes as input a reference to a lvalue and return true. Whereas the second function uses a reference to 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



回答3:


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.

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.

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.

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; with a type, it has to be first converted to bool for the possibility of it being forgotten to happen.




回答4:


Use std::is_lvalue_reference and std::is_rvalue_reference.

You don't need a wrapper if you're happy with using 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:

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.



来源:https://stackoverflow.com/questions/36296425/how-to-determine-programmatically-if-an-expression-is-rvalue-or-lvalue-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!