static_cast
conversion
Convertit entre les types en utilisant une combinaison de conversions implicites et définies par l'utilisateur.
Table des matières |
Syntaxe
static_cast<
type-cible
>(
expression
)
|
|||||||||
Retourne une valeur de type target-type .
Explication
Seules les conversions suivantes peuvent être effectuées avec static_cast , sauf lorsque ces conversions supprimeraient la constance (ou la volatilité).
Base
» et
target-type
est « référence vers
cv2
Derived
», le résultat fait référence à l'objet de type
Derived
englobant
expression
si toutes les conditions suivantes sont satisfaites :
-
Derivedest un type de classe complet. -
Baseest une classe de base deDerived. - cv1 n'est pas une qualification-cv plus forte que cv2 .
-
Baseest une classe de base virtuelle deDerived. -
Baseest une classe de base d'une classe de base virtuelle deDerived. -
Aucune
conversion standard
valide de « pointeur vers
Derived» vers « pointeur versBase» n'existe.
Derived
, le comportement est indéfini.
struct B {}; struct D : B { B b; }; D d; B& br1 = d; B& br2 = d.b; static_cast<D&>(br1); // OK, lvalue désignant l'objet original « d » static_cast<D&>(br2); // UB : le sous-objet « b » n'est pas un sous-objet de classe de base
|
2)
Si
target-type
est une « référence à rvalue vers
Derived
» et
expression
est une xvalue de type « (éventuellement qualifié cv)
Base
» telle que
Base
est une classe de base de
Derived
, le résultat et les contraintes d'une telle conversion sont les mêmes que ceux de la conversion « lvalue
Base
vers référence
Derived
».
3)
Si
target-type
est un type de référence à rvalue et que le type référencé est
compatible par référence
avec le type de
expression
,
static_cast
convertit la valeur de
glvalue, prvalue de classe ou prvalue de tableau
(jusqu'en C++17)
toute lvalue
(depuis C++17)
expression
en xvalue référençant le même objet que l'expression, ou sa sous-objet de classe de base (selon
target-type
).
[1]
Si
target-type
est une base inaccessible ou ambiguë du type de
expression
, le programme est mal formé.
Si
expression
est une lvalue de
champ de bits
, elle est d'abord convertie en prvalue du type sous-jacent.
|
(depuis C++11) |
|
la déclaration target-type temp ( expression ) ; est bien formée pour une variable temporaire inventée temp . L'effet d'une telle conversion explicite est le même que d'effectuer la déclaration et l'initialisation puis d'utiliser temp comme résultat de la conversion. La expression est utilisée comme une lvalue (jusqu'à C++11) une glvalue (depuis C++11) si et seulement si l'initialisation l'utilise comme une lvalue (jusqu'à C++11) une glvalue (depuis C++11) . |
(jusqu'à C++17) | ||
|
l'une des conditions suivantes est satisfaite :
La conversion explicite est définie comme suit :
|
(depuis C++17) |
- conversion lvalue-vers-rvalue
- conversion tableau-vers-pointeur
- conversion fonction-vers-pointeur
- conversion pointeur nul
- conversion pointeur-membre nul
- conversion booléenne
| (depuis C++17) |
|
a)
Une valeur de type
énumération délimitée
peut être convertie en un type entier ou à virgule flottante.
|
(depuis C++11) |
- Si target-type a un type sous-jacent fixe, expression est d'abord convertie en ce type par promotion intégrale ou conversion intégrale , si nécessaire, puis en target-type .
- Si target-type n'a pas de type sous-jacent fixe, la valeur de expression reste inchangée si la valeur originale est dans la plage des valeurs d'énumération , sinon le comportement est indéfini.
|
d)
Une valeur prvalue de type flottant peut être explicitement convertie vers tout autre type flottant.
|
(depuis C++23) |
Base
» peut être explicitement convertie en type « pointeur vers
cv2
Derived
» si toutes les conditions suivantes sont satisfaites :
-
Derivedest un type de classe complet. -
Baseest une classe de base deDerived. - cv1 n'est pas une qualification cv plus forte que cv2 .
Derived
contenant l'objet de type
Base
pointé par
expression
.
-
Baseest une classe de base virtuelle deDerived. -
Baseest une classe de base d'une classe de base virtuelle deDerived. -
Aucune conversion standard valide de « pointeur vers
Derived» vers « pointeur versBase» n'existe.
Derived
, le comportement est indéfini.
Derived
de type
cv1
T
» peut être explicitement convertie en type « pointeur sur membre de
Base
de type
cv2
T
» si toutes les conditions suivantes sont satisfaites :
-
Derivedest un type classe complet. -
Baseest une classe de base deDerived. - cv1 n'est pas une qualification-cv plus forte que cv2 .
Base
.
Base
de type
T
» vers « pointeur vers membre de
Derived
de type
T
» n'existe, le programme est mal formé.
Base
, le comportement est indéfini.
T
» si
T
est un type objet et
cv1
n'est pas une qualification-cv plus forte que
cv2
.
|
(jusqu'en C++17) |
|
(depuis C++17) |
Comme pour toutes les expressions de cast, le résultat est :
- un lvalue si target-type est un type référence lvalue ou une référence rvalue vers un type fonction (depuis C++11) ;
|
(depuis C++11) |
- un prvalue sinon.
- ↑ Ce type de static_cast est utilisé pour implémenter la sémantique de déplacement dans std::move .
- ↑ Si l'arithmétique IEEE est supportée, l'arrondi par défaut est vers la valeur la plus proche.
Objets convertibles par pointeur
Deux objets a et b sont interchangeables par pointeur si :
- ils sont le même objet, ou
- l'un est un objet union et l'autre est un membre de données non statique de cet objet, ou
- l'un est un standard-layout class object et l'autre est le premier membre de données non statique de cet objet ou de tout sous-objet de classe de base de cet objet, ou
- il existe un objet c tel que a et c sont pointer-interconvertible, et c et b sont pointer-interconvertible.
union U { int a; double b; } u; void* x = &u; // la valeur de x est « pointeur vers u » double* y = static_cast<double*>(x); // la valeur de y est « pointeur vers u.b » char* z = static_cast<char*>(x); // la valeur de z est « pointeur vers u »
Notes
Les conversions de base-vers-dérivé (
downcasts
) utilisant
static_cast
n'effectuent aucune vérification à l'exécution pour garantir que le
type dynamique
de l'objet pointé/référencé est
Derived
, et ne peuvent être utilisées en sécurité que si ce prérequis est garanti par d'autres moyens, comme lors de l'implémentation du
polymorphisme statique
. Un downcast sécurisé peut être effectué avec
dynamic_cast
.
static_cast peut également être utilisé pour lever l'ambiguïté des surcharges de fonctions en effectuant une conversion fonction-vers-pointeur vers un type spécifique, comme dans
std::for_each(files.begin(), files.end(), static_cast<std::ostream&(*)(std::ostream&)>(std::flush));
Mots-clés
Exemple
#include <iostream> #include <vector> struct B { int m = 42; const char* hello() const { return "Hello world, this is B!\n"; } }; struct D : B { const char* hello() const { return "Hello world, this is D!\n"; } }; enum class E { ONE = 1, TWO, THREE }; enum EU { ONE = 1, TWO, THREE }; int main() { // 1. conversion descendante statique D d; B& br = d; // conversion ascendante via conversion implicite std::cout << "1) " << br.hello(); D& another_d = static_cast<D&>(br); // conversion descendante std::cout << "1) " << another_d.hello(); // 3. lvalue vers xvalue std::vector<int> v0{1, 2, 3}; std::vector<int> v2 = static_cast<std::vector<int>&&>(v0); std::cout << "3) après déplacement, v0.size() = " << v0.size() << '\n'; // 4. expression à valeur ignorée static_cast<void>(v2.size()); // 5. conversion d'initialisation int n = static_cast<int>(3.14); std::cout << "5) n = " << n << '\n'; std::vector<int> v = static_cast<std::vector<int>>(10); std::cout << "5) v.size() = " << v.size() << '\n'; // 6. inverse de la conversion implicite void* nv = &n; int* ni = static_cast<int*>(nv); std::cout << "6) *ni = " << *ni << '\n'; // 7a. enum délimité vers int E e = E::TWO; int two = static_cast<int>(e); std::cout << "7a) " << two << '\n'; // 7b. int vers enum, enum vers un autre enum E e2 = static_cast<E>(two); [[maybe_unused]] EU eu = static_cast<EU>(e2); // 7f. pointeur vers membre en conversion ascendante int D::*pm = &D::m; std::cout << "7f) " << br.*static_cast<int B::*>(pm) << '\n'; // 7g. void* vers n'importe quel pointeur d'objet void* voidp = &e; [[maybe_unused]] std::vector<int>* p = static_cast<std::vector<int>*>(voidp); }
Sortie :
1) Hello world, this is B! 1) Hello world, this is D! 3) after move, v0.size() = 0 5) n = 3 5) v.size() = 10 6) *ni = 3 7a) 2 7f) 42
1) Bonjour le monde, voici B ! 1) Bonjour le monde, voici D ! 3) après déplacement, v0.size() = 0 5) n = 3 5) v.size() = 10 6) *ni = 3 7a) 2 7f) 42
` n'est pas traduit (comme demandé) - Les termes C++ (`size()`, `move`, `n`, `v`, `ni`) sont conservés - Seul le texte anglais ordinaire a été traduit en français
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 137 | C++98 |
la constance et la volatilité des
pointeurs vers void pouvaient être supprimées par cast |
les qualifications cv ne peuvent pas
être supprimées par cast dans ces cas |
| CWG 427 | C++98 | la conversion descendante pouvait être ambiguë avec l'initialisation directe | sélectionne la conversion descendante dans ce cas |
| CWG 439 | C++98 |
lors de la conversion d'un "pointeur vers objet" en "pointeur vers
void " puis de retour vers lui-même, il ne pouvait préserver sa valeur que si le type résultat avait la même qualification cv |
la qualification cv
peut être différente |
| CWG 1094 | C++98 |
la conversion des valeurs à virgule flottante
vers les valeurs d'énumération n'était pas spécifiée |
spécifiée |
| CWG 1320 | C++11 |
la conversion des valeurs d'énumération scopée
vers bool n'était pas spécifiée |
spécifiée |
| CWG 1412 | C++98 |
le résultat de la conversion de
"pointeur vers void " vers "pointeur vers objet" n'était pas clair |
clarifié |
| CWG 1447 | C++11 |
la conversion des champs de bits vers les références rvalue
n'était pas spécifiée (impossible de lier des références aux champs de bits) |
spécifiée |
| CWG 1766 | C++98 |
la conversion des valeurs entières ou d'énumération vers les valeurs d'énumération
produisait un résultat non spécifié si expression était hors limites |
le comportement est
indéfini dans ce cas |
| CWG 1832 | C++98 |
la conversion des valeurs entières ou d'énumération vers
les valeurs d'énumération autorisait target-type à être incomplet |
non autorisé |
| CWG 2224 | C++98 |
la conversion d'un membre de type classe de base vers
son objet complet de type classe dérivée était valide |
le comportement est
indéfini dans ce cas |
| CWG 2254 | C++11 |
un objet de classe standard-layout sans membres de données
était interconvertible par pointeur avec sa première classe de base |
il est interconvertible par pointeur
avec n'importe laquelle de ses classes de base |
| CWG 2284 | C++11 |
un objet union non standard-layout et un membre de données non statique
de cet objet n'étaient pas interconvertibles par pointeur |
ils le sont |
| CWG 2310 | C++98 |
pour les conversions de pointeur base-vers-dérivé et
les conversions de pointeur-vers-membre dérivé-vers-base, le type classe dérivée pouvait être incomplet |
doit être complet |
| CWG 2338 | C++11 |
la conversion vers les types d'énumération avec type sous-jacent fixe
résultait en un comportement indéfini si expression était hors limites |
convertit d'abord vers le type sous-jacent
(pas de comportement indéfini) |
| CWG 2499 | C++11 |
une classe standard-layout pouvait avoir une classe de base non interconvertible
par pointeur, même si tous les sous-objets de base ont la même adresse |
elle n'en a pas |
| CWG 2718 | C++98 |
pour les conversions de référence base-vers-dérivé,
le type classe dérivée pouvait être incomplet |
doit être complet |
| CWG 2882 | C++98 |
il n'était pas clair si
static_cast
<
void
>
(
expr
)
tente
de former une séquence de conversion implicite de expr vers void |
aucune tentative dans ce cas |
Références
- Norme C++23 (ISO/IEC 14882:2024) :
-
- 7.6.1.9 Conversion statique [expr.static.cast]
- Norme C++20 (ISO/CEI 14882:2020) :
-
- 7.6.1.8 Conversion statique [expr.static.cast]
- Norme C++17 (ISO/IEC 14882:2017) :
-
- 8.2.9 Conversion statique [expr.static.cast]
- Norme C++14 (ISO/CEI 14882:2014) :
-
- 5.2.9 Conversion statique [expr.static.cast]
- Norme C++11 (ISO/IEC 14882:2011) :
-
- 5.2.9 Conversion statique [expr.static.cast]
- Norme C++98 (ISO/CEI 14882:1998) :
-
- 5.2.9 Conversion statique [expr.static.cast]
- Norme C++03 (ISO/IEC 14882:2003) :
-
- 5.2.9 Conversion statique [expr.static.cast]