J'avoue que j'ai du mal à comprendre. Il n'y a rien d'explicite dans la norme :
Citation:
5.2.3 Explicit type conversion (functional notation) [expr.type.conv]
1) A simple-type-specifier (7.1.6.2) or typename-specifier (14.6) followed by a parenthesized expression-list constructs a value of the specified type given the expression list. If the expression list is a single expression, the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding cast expression (5.4). If the type specified is a class type, the class type shall be complete. If the expression list specifies more than a single value, the type shall be a class with a suitably declared constructor (8.5, 12.1), and the expression T(x1, x2, ...) is equivalent in effect to the declaration T t(x1, x2, ...); for some invented temporary variable t, with the result being the value of t as a prvalue.
2) The expression T(), where T is a simple-type-specifier or typename-specifier for a non-array complete object type or the (possibly cv-qualified) void type, creates a prvalue of the specified type, which is value-initialized (8.5; no initialization is done for the void() case). [ Note: if T is a non-class type that is cv-qualified, the cv-qualifiers are ignored when determining the type of the resulting prvalue (3.10). — end note ]
3) Similarly, a simple-type-specifier or typename-specifier followed by a braced-init-list creates a temporary object of the specified type direct-list-initialized (8.5.4) with the specified braced-init-list, and its value is that temporary object as a prvalue.
Pour référence, les erreurs données par clang :
Code:
1 2 3 4 5 6
| error: indirection requires pointer operand ('double' invalid)
double l = (double(int(i))) * double(int(i));
^ ~~~~~~~~~~~~~~
error: C-style cast from 'double' to 'double (int)' is not allowed
double l = (double(int(i))) + double(int(i));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
Dans le premier cas, il essaye de dé-référencer un pointeur dans le second terme, et dans le deuxième cas il voit le premier terme comme la signature d'une fonction. Le code suivant produit la même erreur :
Code:
double l = (double(int i)) + double(int(i));
Dans les deux cas, l’ambiguïté semble provenir du fait que * et + sont aussi des opérateurs unaires, qui semblent prendre le dessus sur l'interprétation en opérateur binaires.
Edit: En fait si, il y a plusieurs passages dans la norme sur les ambiguités liées au cast.
Citation:
6.8 Ambiguity resolution [stmt.ambig]
1) There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion (5.2.3) as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration. [ Note: To disambiguate, the whole statement might have to be examined to determine if it is an expression-statement or a declaration. This disambiguates many examples. [ Example: assuming T is a simple-type-specifier (7.1.6),
Code:
1 2 3 4 5 6 7
| T(a)->m = 7; // expression-statement
T(a)++; // expression-statement
T(a,5)<<c; // expression-statement
T(*d)(int); // declaration
T(e)[5]; // declaration
T(f) = { 1, 2 }; // declaration
T(*g)(double(3)); // declaration |
Citation:
...
3) The disambiguation is purely syntactic; that is, the meaning of the names occurring in such a statement, beyond whether they are type-names or not, is not generally used in or changed by the disambiguation. Class templates are instantiated as necessary to determine if a qualified name is a type-name. Disambiguation precedes parsing, and a statement disambiguated as a declaration may be an ill-formed declaration. If, during parsing, a name in a template parameter is bound differently than it would be bound during a trial parse, the program is ill-formed. No diagnostic is required. [ Note: This can occur only when the name is declared earlier in the declaration. — end note ]
Le passage en rouge est important. Si j'ai bien compris, peu importe que i soit déclaré comme une variable : la "désambigüisation" a lieu avant que soit attribué une sémantique à un nom particulier. Donc au moment où il lit cette ligne, le compilateur voit une ambiguité d'interprétation qui vient à la base du fait que tu aies entouré ton membre de gauche dans des parenthèses : à première vue (si on ne sais pas que i est une variable et pas un type) on peut comprendre ça de deux manières différentes : si i est une variable, alors c'est juste une chaine de conversion, si i est un type, c'est un opérateur de conversion "C-style" qui cherche à convertir en fonction qui retourne un double et prend en paramètre l'adresse d'une fonction qui retourne un int et prend en paramètre un i. :calim2:
Autre passage de la norme sur cette ambiguïté dans un autre contexte :
Citation:
8.2 Ambiguity resolution [dcl.ambig.res]
1) The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in 6.8 can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in 6.8, the resolution is to consider any construct that could possibly be a declaration a declaration. [ Note: a declaration can be explicitly disambiguated by a nonfunction-style cast, by an = to indicate initialization or by removing the redundant parentheses around the parameter name. — end note ]
Code:
1 2 3 4 5 6 7 8 9 10
| struct S {
S(int);
};
void foo(double a) {
S w(int(a)); // function declaration
S x(int()); // function declaration
S y((int)a); // object declaration
S z = int(a); // object declaration
} |
Citation:
2) The ambiguity arising from the similarity between a function-style cast and a type-id can occur in different contexts. The ambiguity appears as a choice between a function-style cast expression and a declaration of a type. The resolution is that any construct that could possibly be a type-id in its syntactic context shall be considered a type-id.
Dans ce contexte, s'il a le choix entre un cast et un type, le compilateur doit considérer qu'une expression est un type.