¿Cómo determinar mediante programación si una expresión es rvalue o lvalue en C++?


¿Cuál es la mejor manera de determinar si una expresión es un rvalue o lvalue en C++? Probablemente, esto no es útil en la práctica, pero ya que estoy aprendiendo rvalues y lvalues pensé que sería bueno tener una función is_lvalue que devuelve true si la expresión pasada en la entrada es un lvalue y false de lo contrario.

Ejemplo:

std::string a("Hello");
is_lvalue(std::string()); // false
is_lvalue(a); // true  
Author: smci, 2016-03-30

4 answers

La mayor parte del trabajo ya está hecho para usted por el stdlib, solo necesita un contenedor de función:

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

En el caso de pasar un std::string lvalue entonces T deducirá a std::string& o const std::string&, para rvalues deducirá a std::string

 57
Author: Ryan Haining,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-27 03:24:28

Resolví la pregunta anterior usando dos funciones de plantilla sobrecargadas. La primera toma como entrada una referencia a un lvalue y devuelve true. Mientras que la segunda función utiliza 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
 25
Author: Giuseppe Pes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-29 23:21:28

Me gustaría tener una página de boost::hana y hacer que el valor de retorno de is_lvalue codificar el lvalue-ness de su argumento tanto como a constexpr valor, y como un tipo.

Esto te permite hacer cosas como el envío de etiquetas sin repeticiones adicionales.

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 es ignorado. Esto permite que sea constexpr incluso en valores no constexpr.

Se puede ver una ventaja de esta técnica 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 el valor de retorno de is_lvalue está disponible en un contexto constexpr (ya que true_type y false_type tienen un constexpr operator bool), sino que podemos elegir fácilmente una sobrecarga basada en su estado.

Otra ventaja es que hace difícil que el compilador no inline el resultado. Con un valor constexpr, el compilador puede 'fácilmente' olvidar que es una constante verdadera; con un tipo, primero tiene que ser convertido a bool para la posibilidad de que se olvide.

 14
Author: Yakk - Adam Nevraumont,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-30 17:59:56

Uso std::is_lvalue_reference y std::is_rvalue_reference.

No necesita un wrapper si está satisfecho 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ías escribir un wrapper como sugiere @Ryan Haining, solo asegúrate de obtener los tipos correctos.

 7
Author: Pharap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-30 18:13:01