Quel est le type de `a? b: c`?

Disons que nous avons

template  struct Foo {}; 

et

 struct Bar { template  operator Foo() const { return Foo(); } }; 

et

 template  Foo Baz(T const&) { return Foo(); } 

Alors true ? Bar() : Baz(some_expr_of_type_double) true ? Bar() : Baz(some_expr_of_type_double) a le type Foo car Bar est convertible en Foo . Cette astuce permet d’interroger le type de some_expr_of_type_double sans l’évaluer.

Quelles sont les règles pour déterminer le type d’ a ? b : c a ? b : c ? J’apprécierais la partie pertinente de la norme (je n’en ai pas de copie). Y at-il plus que ” typeof(b) doit être convertible en typeof(c) ou vice versa, sans ambiguïté”?

Voici la spécification pertinente:

5.16 Opérateur conditionnel [expr.cond]

  1. Groupe d’expressions conditionnelles de droite à gauche. La première expression est implicitement convertie en bool (clause 4). Elle est évaluée et si elle est vraie, le résultat de l’expression conditionnelle est la valeur de la deuxième expression, sinon celle de la troisième expression. Tous les effets secondaires de la première expression, à l’exception de la destruction des temporaires (12.2), se produisent avant l’évaluation de la deuxième ou de la troisième expression. Une seule des deuxième et troisième expressions est évaluée.

  2. Si le deuxième ou le troisième opérande a le type vide (probablement qualifié de cv), alors les conversions standard lvalue-à-valeur (4.1), tableau à pointeur (4.2) et fonction à pointeur (4.3) sont exécutés sur les deuxième et troisième opérandes, et l’un des suivants doit être vérifié:

    – Le deuxième ou le troisième opérande (mais pas les deux) est une expression de projection (15.1); le résultat est du type de l’autre et est une valeur.

    – le deuxième et le troisième opérandes ont tous deux un type vide; le résultat est de type void et est une valeur.

    [Remarque: ceci inclut le cas où les deux opérandes sont des expressions de projection. ]

  3. Sinon, si les deuxième et troisième opérandes ont des types différents et que l’un ou l’autre a un type de classe (éventuellement qualifié de cv), une tentative de conversion de chacun de ces opérandes en type de l’autre est effectuée. Le processus permettant de déterminer si une expression d’opérande E1 de type T1 peut être convertie pour correspondre à une expression d’opérande E2 de type T2 est défini comme suit:

    3.a: Si E2 est une lvalue: E1 peut être converti pour correspondre à E2 si E1 peut être converti implicitement (clause 4) en type “référence à T2”, sous réserve de la contrainte selon laquelle la référence doit être liée directement ( 8.5.3) à E1.

    3.b: Si E2 est une valeur, ou si la conversion ci-dessus ne peut pas être effectuée:

    3.b.1: si E1 et E2 ont un type de classe et que les types de classe sous-jacents sont identiques ou que l’un est une classe de base de l’autre: E1 peut être converti pour correspondre à E2 si la classe de T2 est du même type que, ou une classe de base de, la classe de T1 et la qualification cv de T2 est la même qualification cv que, ou une cv qualification supérieure, la qualification cv de T1. Si la conversion est appliquée, E1 est remplacé par une valeur de type T2 qui fait toujours référence à l’object de classe source d’origine (ou à son sous-object approprié). (Remarque: aucune copie n’est faite.)

    3.b.2: Autrement (c’est-à-dire si E1 ou E2 a un type non-classe, ou s’ils ont tous deux un type de classe mais que les classes sous-jacentes ne sont ni les mêmes ni l’une des classes de base de l’autre): E1 peut être converti en associe E2 si E1 peut être implicitement converti en un type que l’expression E2 aurait si E2 était converti en une valeur rvalue (ou le type dont elle dispose, si E2 est une valeur rvalue).

    En utilisant ce processus, il est déterminé si le deuxième opérande peut être converti pour correspondre au troisième opérande et si le troisième opérande peut être converti pour correspondre au deuxième opérande. Si les deux peuvent être convertis, ou l’un des convertis mais que la conversion est ambiguë, le programme est mal formé. Si aucun des deux ne peut être converti, les opérandes restnt inchangés et une vérification supplémentaire est effectuée comme décrit ci-dessous. Si exactement une conversion est possible, cette conversion est appliquée à l’opérande choisi et l’opérande converti est utilisé à la place de l’opérande d’origine pour le rest de cette section.

  4. Si les deuxième et troisième opérandes sont des valeurs et ont le même type, le résultat est de ce type et est une valeur.

  5. Sinon, le résultat est une valeur. Si les deuxième et troisième opérandes n’ont pas le même type et qu’ils ont soit un type de classe (éventuellement qualifié de cv), la résolution de surcharge sert à déterminer les conversions (le cas échéant) à appliquer aux opérandes (13.3.1.2, 13.6) . Si la résolution de surcharge échoue, le programme est mal formé. Sinon, les conversions ainsi déterminées sont appliquées et les opérandes convertis sont utilisés à la place des opérandes d’origine pour le rest de cette section.

  6. Des conversions standard de valeur de valeur à (4.1), de tableau à pointeur (4.2) et de fonction à pointeur (4.3) sont effectuées sur les deuxième et troisième opérandes. Après ces conversions, l’un des cas suivants doit être conservé:

    6.a: les deuxième et troisième opérandes ont le même type; le résultat est de ce type.

    6.b: les deuxième et troisième opérandes ont un type arithmétique ou énumération; les conversions arithmétiques habituelles sont effectuées pour les amener à un type commun, et le résultat est de ce type.

    6.c: les deuxième et troisième opérandes ont un type de pointeur ou l’un est de type pointeur et l’autre est une constante de pointeur nulle; les conversions de pointeur (4.10) et les conversions de qualification (4.4) sont effectuées pour les amener à leur type de pointeur composite (5.9). Le résultat est du type pointeur composite.

    6.d: les deuxième et troisième opérandes ont un pointeur sur le type de membre, ou l’un a un pointeur sur un type de membre et l’autre est une constante de pointeur nulle; les conversions pointeur vers membre (4.11) et qualification (4.4) sont effectuées pour les amener à un type commun, dont la qualification cv doit correspondre à la qualification cv du deuxième ou du troisième opérande. Le résultat est du type commun.

C’est plus que typeof (b) doit être convertible en typeof (c). C’est un ensemble complexe de règles énoncées dans 5.16: 2-6; environ une page de longueur. Il y a un ordre de tentatives et un tas de trucs sur lvalue vs rvalue.

Avez-vous un compilateur C ++ 0x? Dans ce cas, decltype(a ? b : c) peut-être? Pas sûr que cela gère les références correctement, cependant. N’importe qui?

J’apprécierais la partie pertinente de la norme (je n’en ai pas de copie)

Vous pouvez obtenir gratuitement le projet actuel sur le site Web du WG21 .

La norme (une version actuelle que vous pouvez trouver ici ) explique de manière détaillée, voire nécessairement claire, la procédure de frappe exacte. Ce que je tire de ça, c’est que c’est une expression (BOOL? Y: Z)

il vérifie d’abord le type de conversion implicite ou explicite de Y à Z. Ensuite, il recherche une classe de base similaire ou vérifie si Y peut être converti en classe en Z.

Certes, le standard est assez indigeste et je pourrais être extrêmement éloigné de ce que j’ai lu, mais la partie qui ressort est que nous essayons toujours de convertir Y-> Z. Cela laisserait croire que le résultat est aussi du type Z. Un effet secondaire intéressant de cela est que nous plaçons X = (BOOL? Y: Z) et qu’il existe des conversions Y-> X et Z-> X mais pas de conversion Y-> Z, le programme serait alors incorrect.