Explicit type conversion
Convertit entre les types en utilisant une combinaison de conversions explicites et implicites.
Table des matières |
Syntaxe
(
type-id
)
unary-expression
|
(1) | ||||||||
simple-type-specifier
(
expression-list
(optionnel)
)
simple-type-specifier
(
initializer-list
(optionnel)
)
|
(2) |
(jusqu'en C++11)
(depuis C++11) |
|||||||
simple-type-specifier
{
initializer-list
(optionnel)
}
|
(3) | (depuis C++11) | |||||||
simple-type-specifier
{
designated-initializer-list
}
|
(4) | (depuis C++20) | |||||||
typename
identifier
(
initializer-list
(optionnel)
)
|
(5) | (depuis C++11) | |||||||
typename
identifier
{
initializer-list
(optionnel)
}
|
(6) | (depuis C++11) | |||||||
typename
identifier
{
designated-initializer-list
}
|
(7) | (depuis C++20) | |||||||
Convertit explicitement n'importe quel nombre de valeurs en une valeur du type cible.
| type-id | - | un identifiant de type |
| unary-expression | - | une expression unaire (dont l'opérateur principal n'a pas une précédence supérieure à celle du cast de style C) |
| simple-type-specifier | - | un spécificateur de type simple |
| expression-list | - | une liste d'expressions séparées par des virgules (à l'exception des expressions virgules non parenthésées) |
| initializer-list | - | une liste de clauses d'initialisation séparées par des virgules |
| designated-initializer-list | - | une liste de clauses d'initialisation désignées séparées par des virgules |
| identifier | - | un identifiant (éventuellement qualifié) (incluant les identifiants de modèle ) |
Explication
const_cast
<
type-id
>
(
unary-expression
)
;
static_cast
<
type-id
>
(
unary-expression
)
, avec extensions : un pointeur ou une référence vers une
classe dérivée
est également autorisé à être converti en pointeur ou référence vers une classe de base non ambiguë (et vice versa) même si la classe de base est
inaccessible
(c'est-à-dire que cette conversion ignore le spécificateur d'héritage privé). La même règle s'applique à la conversion d'un
pointeur vers membre
en pointeur vers membre d'une classe de base non virtuelle non ambiguë ;
reinterpret_cast
<
type-id
>
(
unary-expression
)
;
T
, qui est déterminé à partir du type spécifié
et de l'initialiseur
(depuis C++17)
:
|
|
(jusqu'à C++17) | ||
|
|
(depuis C++17) |
- Si la conversion de type fonction est de syntaxe (2) , et qu'il y a exactement une expression entre parenthèses, cette conversion est équivalente à la conversion de style C correspondante.
-
Sinon, si
Test (éventuellement qualifié cv) void , le résultat est une rvalue (jusqu'en C++11) une prvalue (depuis C++11) de type void qui n'effectue aucune initialisation.
|
(jusqu'en C++11) |
|
(depuis C++11) |
-
Sinon, si
Test un type référence, la conversion de type fonction a le même effet que l'initialisation directe d'une variable inventée t de typeTà partir de l'initialiseur spécifié, et le résultat est le t initialisé.
|
(jusqu'en C++11) |
|
(depuis C++11) |
-
Sinon, le résultat est
une rvalue
(jusqu'en C++11)
une prvalue
(depuis C++11)
de type
Tdésignant un temporaire (jusqu'en C++17) dont l'objet résultat est (depuis C++17) initialisé directement avec l'initialiseur spécifié.
Résolution d'Ambiguïté
Instruction de déclaration ambiguë
En cas d'ambiguïté entre une instruction d'expression avec une expression de conversion de style fonction comme sous-expression la plus à gauche et une instruction de déclaration, l'ambiguïté est résolue en la traitant comme une déclaration. Cette désambiguïsation est purement syntaxique : elle ne prend pas en compte la signification des noms apparaissant dans l'instruction, sauf pour déterminer s'ils sont des noms de type :
struct M {}; struct L { L(M&); }; M n; void f() { M(m); // déclaration, équivalent à M m; L(n); // déclaration mal formée, équivalent à L n; L(l)(m); // toujours une déclaration, équivalent à L l((m)); }
|
Cependant, si le déclarateur le plus externe dans l'instruction de déclaration ambiguë possède un type de retour trailing , l'instruction ne sera traitée comme une instruction de déclaration que si le type de retour trailing commence par auto : struct M; struct S { S* operator()(); int N; int M; void mem(S s) { auto(s)()->M; // expression (S::M cache ::M), invalide avant C++23 } }; void f(S s) { { auto(s)()->N; // expression, invalide avant C++23 auto(s)()->M; // déclaration de fonction, équivalent à M s(); } { S(s)()->N; // expression S(s)()->M; // expression } } |
(depuis C++11) |
Paramètre de fonction ambigu
L'ambiguïté ci-dessus peut également se produire dans le contexte d'une déclaration. Dans ce contexte, le choix se situe entre une déclaration d'objet avec un cast de style fonction comme initialiseur et une déclaration impliquant un déclarateur de fonction avec un ensemble redondant de parenthèses autour d'un nom de paramètre. La résolution consiste également à considérer toute construction, telle que la déclaration de paramètre potentielle, qui pourrait possiblement être une déclaration comme étant une déclaration :
struct S { S(int); }; void foo(double a) { S w(int(a)); // déclaration de fonction : possède un paramètre `a` de type int S x(int()); // déclaration de fonction : possède un paramètre sans nom de type int(*)() // qui est ajusté à partir de int() // Méthodes pour éviter l'ambiguïté : S y((int(a))); // déclaration d'objet : parenthèses supplémentaires S y((int)a); // déclaration d'objet : cast de style C S z = int(a); // déclaration d'objet : aucune ambiguïté pour cette syntaxe }
|
Cependant, si le déclarateur le plus externe dans la déclaration de paramètre ambiguë possède un type de retour en suffixe , l'ambiguïté ne sera résolue en le traitant comme une déclaration que s'il commence par auto : typedef struct BB { int C[2]; } *B, C; void foo() { S a(B()->C); // déclaration d'objet : B()->C ne peut pas déclarer un paramètre S b(auto()->C); // déclaration de fonction : possède un paramètre sans nom de type C(*)() // qui est ajusté à partir de C() } |
(depuis C++11) |
Identifiant de type ambigu
Une ambiguïté peut survenir de la similarité entre un cast de style fonction et un type-id . La résolution est que toute construction qui pourrait possiblement être un type-id dans son contexte syntaxique doit être considérée comme un type-id :
// `int()` et `int(unsigned(a))` peuvent tous deux être analysés comme type-id : // `int()` représente une fonction retournant int // et ne prenant aucun argument // `int(unsigned(a))` représente une fonction retournant int // et prenant un argument de type unsigned void foo(signed char a) { sizeof(int()); // type-id (incorrect) sizeof(int(a)); // expression sizeof(int(unsigned(a))); // type-id (incorrect) (int()) + 1; // type-id (incorrect) (int(a)) + 1; // expression (int(unsigned(a))) + 1; // type-id (incorrect) }
|
Cependant, si le abstract-declarator le plus externe dans le type-id ambigu possède un trailing return type , l'ambiguïté ne sera résolue en le traitant comme un type-id que s'il commence par auto : typedef struct BB { int C[2]; } *B, C; void foo() { sizeof(B()->C[1]); // OK, sizeof(expression) sizeof(auto()->C[1]); // error: sizeof of a function returning an array } |
(depuis C++11) |
Notes
| Macro de test de fonctionnalité | Valeur | Std | Fonctionnalité |
|---|---|---|---|
__cpp_auto_cast
|
202110L
|
(C++23) | auto ( x ) et auto { x } |
Exemple
#include <cassert> #include <iostream> double f = 3.14; unsigned int n1 = (unsigned int)f; // C-style cast unsigned int n2 = unsigned(f); // function-style cast class C1; class C2; C2* foo(C1* p) { return (C2*)p; // casts incomplete type to incomplete type } void cpp23_decay_copy_demo() { auto inc_print = [](int& x, const int& y) { ++x; std::cout << "x:" << x << ", y:" << y << '\n'; }; int p{1}; inc_print(p, p); // prints x:2 y:2, because param y here is an alias of p int q{1}; inc_print(q, auto{q}); // prints x:2 y:1, auto{q} (C++23) casts to prvalue, // so the param y is a copy of q (not an alias of q) } // In this example, C-style cast is interpreted as static_cast // even though it would work as reinterpret_cast struct A {}; struct I1 : A {}; struct I2 : A {}; struct D : I1, I2 {}; int main() { D* d = nullptr; // A* a = (A*)d; // compile-time error A* a = reinterpret_cast<A*>(d); // this compiles assert(a == nullptr); cpp23_decay_copy_demo(); }
Sortie :
x:2 y:2 x:2 y:1
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Appliqué à | Comportement publié | Comportement corrigé |
|---|---|---|---|
|
CWG 1223
( P2915R0 ) |
C++11 | l'ajout du type de retour en suffixe introduisait plus d'ambiguïtés | les résout |
| CWG 1893 | C++11 | le cast de style fonction ne prenait pas en compte les expansions de pack | les prend en compte |
| CWG 2351 | C++11 | void { } était mal formé | rendu bien formé |
| CWG 2620 | C++98 |
la résolution des paramètres de fonction ambigus
pouvait être mal interprétée |
amélioration de la formulation |
| CWG 2828 | C++98 |
un cast de style C était mal formé si plusieurs interprétations
d'un static_cast suivi d'un const_cast existaient, indépendamment de l'utilisation réelle de ces conversions |
ne considère que les
conversions potentiellement utilisées |
| CWG 2894 | C++98 | les casts de style fonction pouvaient créer des rvalues de référence | ne peuvent créer que des lvalues de référence |
Références
- Norme C++23 (ISO/CEI 14882:2024) :
-
- 7.6.1.4 Conversion explicite de type (notation fonctionnelle) [expr.type.conv]
-
- 7.6.3 Conversion explicite de type (notation de cast) [expr.cast]
- Norme C++20 (ISO/CEI 14882:2020) :
-
- 7.6.1.4 Conversion explicite de type (notation fonctionnelle) [expr.type.conv]
-
- 7.6.3 Conversion explicite de type (notation de cast) [expr.cast]
- Norme C++17 (ISO/CEI 14882:2017) :
-
- 8.2.3 Conversion de type explicite (notation fonctionnelle) [expr.type.conv]
-
- 8.4 Conversion de type explicite (notation de cast) [expr.cast]
- Norme C++14 (ISO/CEI 14882:2014) :
-
- 5.2.3 Conversion de type explicite (notation fonctionnelle) [expr.type.conv]
-
- 5.4 Conversion de type explicite (notation de cast) [expr.cast]
- Norme C++11 (ISO/CEI 14882:2011) :
-
- 5.2.3 Conversion de type explicite (notation fonctionnelle) [expr.type.conv]
-
- 5.4 Conversion de type explicite (notation de cast) [expr.cast]
- Norme C++03 (ISO/CEI 14882:2003) :
-
- 5.2.3 Conversion explicite de type (notation fonctionnelle) [expr.type.conv]
-
- 5.4 Conversion explicite de type (notation de cast) [expr.cast]
- Norme C++98 (ISO/CEI 14882:1998) :
-
- 5.2.3 Conversion explicite de type (notation fonctionnelle) [expr.type.conv]
-
- 5.4 Conversion explicite de type (notation de cast) [expr.cast]
Voir aussi
const_cast
conversion
|
ajoute ou supprime const |
static_cast
conversion
|
effectue des conversions basiques |
dynamic_cast
conversion
|
effectue des conversions polymorphes vérifiées |
reinterpret_cast
conversion
|
effectue des conversions générales de bas niveau |
| conversions standard | conversions implicites d'un type à un autre |
|
documentation C
pour
opérateur de cast
|
|