2015-08-29 4 views
1

J'ai lu moderne et efficace C++ et la chose suivante a attiré mon attention:Lvalue/rvalue -nes codant pour des références universelles

Dans l'article 28 Scott écrit:

Ensemble, ces observations sur universel références et encodage lvalue/rvalue signifient que pour ce modèle

template<typename T> void func(T&& param);

le paramètre T modèle déduit sera en code si l'argument passé à param était une lvalue ou un rvalue. Le mécanisme de codage est simple. Lorsqu'une valeur lvalue est passée en argument, T est déduite pour être une référence lvalue. Quand un rvalue est passé, T est déduit pour être une non-référence. (Note de l'asymétrie: lvalues ​​sont codées comme références lvalue, mais rvalues ​​sont codés comme non-références.)

Quelqu'un peut-il expliquer pourquoi un tel mécanisme de codage a été choisi? Je veux dire que si nous allons suivre les règles de réduction de référence que l'utilisation du modèle ci-dessus avec rvalue donne la référence rvalue. Et pour autant que je sache, tout fonctionnerait exactement de la même façon s'il était déduit comme référence. Pourquoi est-il codé comme non-référence?

+0

BTW, le terme «référence universelle» ne s'est pas accroché, et le comité a choisi d'utiliser [référence de transfert] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/ 2014/n4164.pdf) à la place. –

+0

Je pense que votre question pourrait être la même que celle-ci http://stackoverflow.com/questions/32282705/a-failure-to-instantiate-function-templates-due-to-universal-forward-reference – aldr

+0

Voir http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm esp. #7. IIRC, Howard Hinnant a déjà déclaré que l'introduction de '&&&' uniquement pour la transmission de références ne serait probablement pas acceptée à ce moment-là (en tant que troisième type de référence). – dyp

Répondre

0

Disons que vous devez passer param autour. En fait, vous devez le stocker à des fins de vie. Comme il est, vous souhaitez simplement utiliser T:

template <typename T> 
struct store { T val; }; 

template<typename T> void func(T&& param) { 
    store<T> s{std::forward<T>(param)}; 
} 

Cela fonctionne parce que si param suis fait passer par dans lvalue, T serait un type de référence lvalue, et nous vous copiez simplement la référence. Si param a été passé par rvalue, nous devons prendre la propriété - T est un type de non-référence, donc nous finissons par construire-déplacer en s.

Le fait que je peux utiliser T ici comme argument de modèle pour store, au lieu de std::conditional_t<std::is_lvalue_reference<T>::value, T, std::remove_reference_t<T>> est probablement pas un accident.

+1

Je ne comprends pas votre réponse. Si 'store ' est détruit après le retour de 'func', alors passer dans les références rvalue fonctionnerait aussi bien que passer dans les références lvalue. Si 'store ' est conservé après le retour de 'func', alors les références lvalue peuvent aussi être invalidées comme peuvent l'être les références rvalue. – hvd

+0

Je pense que le point était qu'il est simplement plus simple de travailler avec T qu'avec T &&, donc à condition de pouvoir obtenir la même fonctionnalité avec T, on en déduit T. – Stvad

0

Je pense que vous pensez à tort. Au lieu de demander "pourquoi ne pas toujours faire T un type de référence", regardez-le de l'autre côté:

Supposons que vous ayez template <typename T> void f(T&&t).

Appelé comme int i; f(i);, certains T est nécessaire de sorte que T&& résout à int&. Quel est le plus simple T qui peut atteindre cet objectif? C'est int&.

Appelé comme f(0);, certains T est nécessaire de sorte que T&& résout à int&&. Quel est le plus simple T qui peut atteindre cet objectif? C'est int, pas int&&.

int&& n'a tout simplement aucun avantage ici.