left assignment c++ c++11 lvalue rvalue

assignment - ¿Cómo determinar programáticamente si una expresión es rvalue o lvalue en C++?



lvalue required as left operand of assignment (4)

¿Cuál es la mejor manera de determinar si una expresión es un valor r o valor l en C ++? Probablemente, esto no es útil en la práctica, pero dado que estoy aprendiendo valores y valores, pensé que sería bueno tener una función is_lvalue que devuelve verdadero si la expresión que se pasa en la entrada es un valor l y falsa en caso contrario.

Ejemplo:

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


La mayor parte del trabajo ya está hecho para ti por stdlib, solo necesitas un contenedor de funciones:

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

en el caso de que pase un std::string lvalue, T deducirá std::string& o const std::string& , para rvalues ​​deducirá std::string


Resolví la pregunta anterior usando dos funciones de plantilla sobrecargadas. El primero toma como entrada una referencia a un valor l y devuelve true . Mientras que la segunda función usa una referencia a rvalue. Luego dejo que el compilador coincida con la función correcta dependiendo de la expresión pasada como entrada.

Código:

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

Salida:

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


Tomaría una página de boost::hana y haré que el valor de retorno de is_lvalue codifique el valor is_lvalue de su argumento como un valor constexpr y como un tipo.

Esto le permite hacer cosas como el despacho de etiquetas sin una repetición adicional.

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

el cuerpo de esta función no hace nada, y el valor del parámetro se ignora. Esto permite que sea uniforme incluso en valores no constexpr.

Una ventaja de esta técnica se puede ver aquí:

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

No solo está disponible el valor de retorno de is_lvalue en un contexto constexpr (como true_type y false_type tienen un constexpr operator bool ), sino que podemos elegir fácilmente una sobrecarga en función de su estado.

Otra ventaja es que dificulta al compilador no alinear el resultado. Con un valor constexpr , el compilador puede ''fácilmente'' olvidar que es una constante verdadera; con un tipo, primero tiene que convertirse a bool para que se olvide suceda.


Use std::is_lvalue_reference y std::is_rvalue_reference .

No necesita un contenedor si está contento con el uso de decltype.

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

En C ++ 17, podrás usar lo siguiente:

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

O podría escribir un contenedor como lo sugiere @Ryan Haining, solo asegúrese de obtener los tipos correctos.