54 votes

Comment déterminer par programme si une expression est rvalue ou lvalue en C ++?

Quel est le meilleur moyen de déterminer si une expression est une valeur rvalue ou une valeur lvalue en C ++? Cela n’est probablement pas utile en pratique, mais comme j’apprends des valeurs et des valeurs, j’ai pensé qu’il serait bien d’avoir une fonction is_lvalue qui renvoie true si l’expression passée en entrée est une valeur et false sinon.

Exemple:

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

69voto

Ryan Haining Points 5355

La plupart du travail est déjà fait pour vous par stdlib, vous avez juste besoin d'un wrapper de fonction:

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

si vous passez une chaîne lvalue, T déduira à std::string& ou const std::string& , pour les valeurs, il déduira à std::string

30voto

Giuseppe Pes Points 4092

J'ai résolu la question ci-dessus en utilisant deux fonctions de modèle surchargées. Le premier prend en entrée une référence à une valeur et renvoie true . Tandis que la seconde fonction utilise une référence à rvalue. Ensuite, je laisse le compilateur correspondre à la fonction correcte en fonction de l'expression passée en entrée.

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

Sortie:

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

21voto

Yakk Points 31636

Je voudrais prendre une page de boost::hana et de rendre la valeur de retour de l' is_lvalue encoder la lvalue-ness de sa thèse, à la fois en tant que constexpr de la valeur, et comme un type.

Cela vous permet de faire des trucs comme balise de dispatching, sans supplément de passe-partout.

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

le corps de cette fonction ne fait rien, et la valeur du paramètre est ignoré. Cela lui permet d'être constexpr même sur la non-constexpr valeurs.

Un avantage de cette technique peut être vu ici:

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

Non seulement la valeur de retour de l' is_lvalue disponible en constexpr contexte true_type et false_type ont un constexpr operator bool), mais on peut facilement choisir une surcharge basée sur son état.

Un autre avantage est que cela rend difficile pour le compilateur de ne pas insérer le résultat. Avec un constexpr de la valeur, le compilateur peut "facilement" d'oublier que c'est une véritable constante; avec un type, il faut d'abord converti en bool pour la possibilité d'être oublié de se produire.

8voto

Pharap Points 804

Utiliser std::is_lvalue_reference et std::is_rvalue_reference.

Vous n'avez pas besoin d'un wrapper si vous êtes heureux avec l'aide 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 vous serez en mesure d'utiliser les éléments suivants:

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

Ou vous pourriez écrire un wrapper comme @Ryan Haining suggère, assurez-vous d'obtenir le type correct.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X