9
votes

Quelle clause standard manda-t-elle cette conversion de lvalue à rvalue?

donné:

int main() {
   int x = 0;
   int y = x; // <---
}


9 commentaires

Je ne pense pas que de telles conversions ont lieu. En tout cas, ce sont des types primitifs, mais même si vous aviez des constructeurs non triviaux, ce que vous avez écrit invoquerait la copie, jamais le constructeur de déplacement.


Discussion à chat.stackoverflow.com/transcript/message/847067#847067 peut être pertinent.


@Kerrek: Mais la valeur doit être utilisée. Comment une telle conversion peut-elle pas avoir lieu? (Et il n'y a pas de constructeur de mouvement en 2003).


@Tomalak: Je vois ... Alors, c'est juste une chose sémantique à l'intérieur du compilateur, ou la conversion a-t-elle des effets visibles?


@Kerrek: J'espère bien que cela n'a aucun effet!


@TOMALAK: Je pense que si un opérateur d'affectation avait besoin d'une r devale, il serait mentionné en 5.17, et ce n'est pas mentionné.


@Tomalak: À moins que ce soit ce que signifie 5,17 / 2 "en simple affectation (=), la valeur de l'expression remplace celle de l'objet mentionné par l'opérande gauche."


@Trutheality: voir, il semble ambigu>. <


@Tomalak: Je pense avoir trouvé la citation pertinente en 8.5 / 14, elle est assez similaire à la citation de 5.17/2 ci-dessus, faisant référence à l'initialisation plutôt que à la mission.


5 Réponses :


2
votes

Est-ce ce que vous recherchez:

§3.10 / 7

Chaque fois qu'un lvalue apparaît dans un contexte où une r devale est attendue, la lvalue est convertie en une r devalue; Voir 4.1, 4.2 et 4.3.

et je pense que lorsque vous écrivez int y = x , il copie essentiellement la la valeur contenu dans l'objet x qui est un lvalue, Mais la valeur est une r devalue, d'où le contexte attend un rvalue.

§4.1 / 2 dit,

La valeur contenue dans l'objet indiqué par la LValue est le résultat de la rapession.

Peut-être que ces deux citations clarifient votre doute. Corrigez-moi si ma compréhension est fausse. Je voudrais apprendre nouveaux choses.


Commentaire de Tomalak:

Mon problème avec c'est que INT & Y = X; est valable, donc dans ce cas de cours x peut ne pas être une rvalue. Je ne sais pas à quel point la différence dans mon exemple fait ne pas perfectionner cela, bien que

Eh bien int & y = x ne copie pas la valeur. Cela crée juste un alias de l'objet lui-même. Mais comme j'ai précédemment dit int y = x , fondamentalement copies la valeur qui est une r devalue. Par conséquent, le contexte attend un rvalue, comme une copie est en cours.


6 commentaires

Presque, mais où est-ce qu'une r devalue?


Mon problème avec c'est que int & y = x; est valide, donc dans ce cas de cours x peut ne pas être un rvalue . Je ne sais pas à quel point la différence dans mon exemple en fait une certaine pertinence.


@Tomalak Geret'kal: J'ai déjà répondu à cette question ci-dessus, l'affectation entière (affectation pour toute classe définie par l'utilisateur) prend l'argument latéral droit en tant que rvalue. Sinon, int x = 5; ne serait pas valide, car 5 est une r devalue et une rvalue ne peut pas être convertie en une lvalue.


@Downvoter: Je ne comprends pas la raison du bowvote. Pourriez-vous me le signaler?


@Tomalak Geret'kal: Si le commentaire "Affectation! = Initialisation" fait référence à mon commentaire ci-dessus, vous avez raison de ne pas être identiques et que j'ai mal utilisé le terme, et pourtant, le commentaire se tient. Substituez «Affectation» pour «initialisation» dans le commentaire et vous êtes défini.


@David: Excellent. Mon vérification valait la peine. :)



9
votes

Je trouve plus facile (s'il est peut-être pas 100% précis) de penser à Lvalue-S en tant que vrais objets et de rvalue-S comme valeur stockée dans l'objet. L'expression x est une expression de lvalue qui fait référence à l'objet x défini dans la première ligne, mais lorsqu'il est utilisé comme côté droit d'une affectation à un type qui n'est pas Un type défini par l'utilisateur La valeur est lue, et c'est là que la conversion de Lvalue vers RValue est effectuée: lisant le contenu de l'objet.

sur la clause spécifique de la norme qui dicte Cette conversion ... Eh bien, le plus proche que je puisse penser, c'est 4.1 [CONV.LVALUE] / 2 (LVALUE À LA CONVERSION DE RVALUE):

La valeur contenue dans l'objet indiqué par la LValue est le résultat de la rapession.

L'exigence que le côté droit de la mission est une r devalue est implicite ou manquant à partir de 5.17 [expr.ass], mais c'est le cas ou l'expression suivante serait une erreur depuis le RHS est une rvalue et il n'y a pas de conversion de rvalue à lvalue: xxx

EDIT: Pour l'initialisation, 8,5 [DCL.Init] / 14, dernière balle (qui fait référence à fondamentale types) états (mines): emphasis

  • Sinon, la valeur initiale de l'objet étant initialisée est la (éventuellement convertie) valeur de l'expression d'initialisation. [...]

    Ce valeur il signifie que l'expression lvalue dans votre exemple est lire (par exemple converti en un rvalue). En tout cas l'alinéa précédent qui faisait référence à la cession pourrait être appliquée ici: si l'initialisation a nécessité une lvalue au lieu d'un rvalue , l'expression int i = 0; < / code> serait mal formé.


4 commentaires

Joli. Je pense que c'est une déduction assez solide. :)


"L'exigence que le côté droit de la mission est une rvalue est implicite ou manquant à partir de 5,17 [expr.ass], mais c'est le cas ou l'expression suivante serait une erreur puisque le RHS est une r devalue et il y a Aucune conversion de rvalue à lvalue "<- cela ne suit pas entièrement, logiquement. "RHS doit être une rvalue, ou le RHS doit être un lvalue (et ce dernier ne peut pas être vrai, donc le premier doit être)" est ce que vous dites; On dirait une fausse dichotomie pour moi?


@Tomalak: Non, le raisonnement est que le côté droit de l'expression est nécessaire pour être soit un lvalue ou une rapalité, mais pas les deux. Maintenant: si le côté droit de l'expression devait être une expression de lvalue, alors i = 5 échouerait; Cette expression est valide (n'a pas échoué), Ergo Le côté droit de l'expression ne peut pas être nécessaire pour être un lvalue . Étant donné que la seule autre option est une rvalue (au moins en C ++ 03), l'expression x = y prend une lvalue comme LHS (ceci est explicite dans la norme ) et une rvalue comme RHS (je n'ai pas pu trouver de citation précise pour cela)


Pourquoi ne peut-il pas être soit selon le contexte?



1
votes

3.10 LVALUES ET RVALUES

1 Chaque expression est soit une lvalue ou une rvalue.

2 Un lvalue fait référence à un objet ou fonction. Une certaine rvalue expressions - celles de la classe ou Type de classe CVQualifiée - Reportez-vous également à Objets.47)

3 [Note: Quelques opérateurs intégrés et Les appels de fonction donnent des lvalues. [Exemple: si e est une expression de Type de pointeur, alors * e est un lvalue expression faisant référence à l'objet ou fonction à laquelle e points. Comme un autre exemple, la fonction Int & F (); rendements un lvalue, donc l'appel f () est un expression de lvalue. ]

  1. [Note: Certains opérateurs Builin s'attendent à des opérandes de Lvalue. [Exemple: intégré Les opérateurs d'affectation s'attendent tous à leur les opérandes de gauche doivent être des lvalues. ] Les autres opérateurs intégrés produisent des r devalues, Et certains attendent-les. [Exemple: le Les opérateurs unis et binaires + attendent Avalue Arguments et rendement RValue résultats. ] La discussion de chaque L'opérateur intégré à l'article 5 indique si cela s'attend à ce que les opérandes de lvalue et que ce soit de la nièce de lvalue. ]

    5 le résultat de l'appel d'une fonction cela ne renvoie pas une référence est un rvalue. Les opérateurs définis par l'utilisateur sont fonctions, et si ces opérateurs attendre ou donner des lvalues ​​de rendement est déterminé par leurs types de paramètres et de retour.

    6 une expression qui détient un Objet temporaire résultant d'une distribution à un type de non-référence est une r devalue (Cela inclut la création explicite d'un objet utilisant la notation fonctionnelle (5.2.3)).

    7 Chaque fois qu'un lvalue apparaît dans un contexte où une r devale est attendue, Le lvalue est converti en une r devalue; Voir 4.1, 4.2 et 4.3.

    8 la discussion de référence initialisation en 8.5.3 et de Les temporaires en 12.2 indiquent la comportement des lvalues ​​et des rapaces dans autres contextes importants.

    9 rvalues ​​de classe peut avoir CVqualifiée les types; Les ruvales non classes ont toujours types cvunqualifié. Les rabais doivent toujours avoir des types complets ou le vide taper; En plus de ces types, Les lvalues ​​peuvent également avoir incomplet Types.

    10 un lvalue pour un objet est nécessaire pour modifier le objet sauf qu'un rvalue de classe type peut également être utilisé pour modifier son référent dans certaines circonstances. [Exemple: une fonction de membre appelée Un objet (9.3) peut modifier l'objet. ]

    11 Les fonctions ne peuvent pas être modifiées, mais Les pointeurs vers des fonctions peuvent être modifiable.

    12 un pointeur à un type incomplet peut être modifiable. À un moment de la programme lorsque le point indiqué à tapez est complet, l'objet auquel le Les points de pointeur peuvent également être modifiés.

    13 Le référent d'un Consqualifié L'expression ne doit pas être modifiée (à travers cette expression), sauf que Si c'est du type de classe et a un composant mutable, ce composant peut être modifié (7.1.5.1).

    14 Si une expression peut être utilisée pour modifier l'objet auquel il fait référence, L'expression est appelée modifiable. UNE programme qui tente de modifier un objet à travers une lvalue non chargée ou expression de rvalue est malformée.

    15 Si un programme tente d'accéder à la valeur stockée d'un objet à travers un lvalue d'autre que l'un des Types suivants Le comportement est indéfinle48): - le type dynamique de l'objet, - une version CVQualifiée de le type dynamique de l'objet, - a Tapez qui est le signé ou non signé Tapez correspondant au type dynamique de l'objet, - un type qui est le type signé ou non signé correspondant à une version cvalifiée de la type dynamique de l'objet, - un Type d'agrégat ou d'union qui comprend un des types susmentionnés parmi ses membres (y compris, récursivement, un membre d'un sous-assemblée ou contenu Union), - un type qui est (éventuellement cvqualified) Type de classe de base de la type dynamique de l'objet, - un char ou type de caractère non signé.


0 commentaires

8
votes

i les croyez que cela est intuitif dans une certaine mesure (ce que les autres ont déjà dit - la valeur est nécessaire, donc il est donc nécessaire de convertir le concepteur d'objet en la valeur qui y est contenue). Le meilleur que je pouvais trouver, à 4p3:

Une expression e peut être implicitement convertie en un type T si et uniquement si la déclaration "t t = e;" est bien formé, pour une variable temporaire inventée T (8,5). L'effet de la conversion implicite est la même chose que l'exécution de la déclaration et de l'initialisation, puis en utilisant la variable temporaire à la suite de la conversion. Le résultat est un lvalue si T est un type de référence (8.3.2) et une r devalue autrement. L'expression e est utilisée comme une lvalue si et uniquement si l'initialisation l'utilise comme une lvalue.

Notez le "Si et seulement si" à la fin - L'initialisateur est utilisé comme une rvalue , car l'initialisation l'utilise comme une rvalue (résultat de la conversion). Donc, à 3.10P7

Chaque fois qu'un lvalue apparaît dans un contexte où une r devale est attendue, la lvalue est convertie en une r devalue; Voir 4.1, 4.2 et 4.3.


Edit: Le paragraphe de saisie de 4P3 peut être trouvé au 8.5p16, dernière balle:

Sinon, la valeur initiale de l'objet étant initialisée est la valeur (éventuellement convertie) de l'expression d'initialisation.

Notez également les commentaires ci-dessous.


5 commentaires

Mais y a-t-il une conversion du tout? Vous commencez par un int et vous vous retrouvez avec un int . Par ce raisonnement seul, je ne suis pas sûr que la première citation s'applique.


@Tomalak Une conversion ne commence pas vraiment avec un type, mais avec une expression . Et l'expression est convertie d'un LValue Int à une rvalue d'int.


@LitB: C'est la logique circulaire. "Il y a une conversion, à cause de cette règle parlant de ce qui se passe lorsqu'une conversion est requise."


@Tomalak Je suis d'accord qu'un raisonnement aussi circulaire peut être trouvé. Il peut être argumenté d'être circulaire. On peut également soutenir que ce paragraphe ne parle pas de une conversion implicite "", mais plutôt d'une séquence de conversion implicite . C'est-à-dire une séquence de conversions ou aucune conversion du tout. Sinon, 0 n'a pas pu être "implicitement converti" en une prvalue de type int , ce qui serait faux parce que int A = 0 est bien formé. Je pense que c'est une hypothèse raisonnable à mettre dans le libellé - le paragraphe n'empêche évidemment pas les séquences qui contiennent deux conversions ou plus.


@LitB: Non, mais cela n'apporte pas non plus de mandat que la séquence de conversion entre dans la photo en premier lieu, dans le scénario donné. Vous avez l'étape d'induction triée, mais il manque toujours un cas de base. :)



2
votes

L'initialisateur a la grammaire de Follwing: xxx

dans votre exemple, x est un affectation-expression qui suit cette chaîne de Productions de la grammaire: xxx

et un identifiant "est un lvalue si l'entité est une fonction ou une variable" (expressions primaires "5.1 / 4").

Donc, dans votre exemple, l'expression à droite du = est une expression qui se trouve être un lvalue . Cela pourrait être un rvalue bien sûr, mais cela ne doit pas être. Et il n'y a pas de conversion obligatoire de lvalue-to-rvalue.

Je ne sais pas quelle est la valeur en sachant que c'est, cependant.


0 commentaires