How to determine programmatically if an expression has a rvalue or lvalue value in C ++?

What is the best way to determine if an expression is rvalue or lvalue in C ++? This is probably not useful in practice, but since I am studying rvalues ​​and lvalues, I thought it would be nice to have an is_lvalue function that returns true if the expression passed in the input is lvalue and false otherwise.

Example:

 std::string a("Hello"); is_lvalue(std::string()); // false is_lvalue(a); // true 
+49
c ++ c ++ 11 rvalue lvalue
Mar 29 '16 at 22:43
source share
4 answers

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

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

if you pass the value of std::string , then T will output the value of std::string& or const std::string& , and for the values ​​of r, std::string

Note that the Yakk answer will return a different type, which provides more flexibility, and you should read this answer and probably use it instead.

+60
Mar 29 '16 at 23:17
source share

I solved the above question using two overloaded template functions. The first takes as a reference a link to lvalue and returns true . While the second function uses the rvalue reference. Then I let the compiler match the correct function depending on the expression passed as input.

the 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 
+26
Mar 29 '16 at 22:43
source share

I would take the page from boost::hana and make the return value is_lvalue encoded the lvalue-ness of my argument as both a constexpr value and a type.

This allows you to do something like send tags without an additional template.

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

the body of this function does nothing, and the value of the parameter is ignored. This allows it to be constexpr even for values ​​other than constexpr.

The 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_lvalue return value is_lvalue available in the context of constexpr (since true_type and false_type have constexpr operator bool ), but we can easily choose overload depending on its state.

Another advantage is that the compiler makes it difficult to not embed the result. With a value of constexpr compiler can β€œeasily” forget that it is a true constant; with a type, it must first be converted to a bool order to be forgotten.

+16
Mar 30 '16 at 14:34
source share

Use std::is_lvalue_reference and std::is_rvalue_reference .

You do not need a shell if you are satisfied 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 can 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 can write a wrapper as @Ryan Haining suggests, just make sure you set the types correctly.

+8
Mar 30 '16 at 7:34
source share



All Articles