Implicit conversions
Les conversions implicites sont effectuées chaque fois qu'une expression d'un certain type
T1
est utilisée dans un contexte qui n'accepte pas ce type, mais qui accepte un autre type
T2
; en particulier :
-
lorsque l'expression est utilisée comme argument lors de l'appel d'une fonction déclarée avec
T2comme paramètre ; -
lorsque l'expression est utilisée comme opérande avec un opérateur qui attend
T2; -
lors de l'initialisation d'un nouvel objet de type
T2, y compris l'instructionreturndans une fonction retournantT2; -
lorsque l'expression est utilisée dans une instruction
switch
(
T2est un type intégral) ; -
lorsque l'expression est utilisée dans une instruction
if
ou une boucle (
T2est bool ).
Le programme est bien formé (se compile) uniquement s'il existe une séquence de
conversion implicite
non ambiguë de
T1
vers
T2
.
S'il existe plusieurs surcharges de la fonction ou de l'opérateur appelé, après la construction de la séquence de conversion implicite de
T1
vers chaque
T2
disponible,
les règles de résolution de surcharge
déterminent quelle surcharge est compilée.
Note : dans les expressions arithmétiques, le type de destination pour les conversions implicites des opérandes des opérateurs binaires est déterminé par un ensemble distinct de règles : usual arithmetic conversions .
Table des matières |
Ordre des conversions
La séquence de conversion implicite se compose des éléments suivants, dans cet ordre :
Lorsqu'on considère l'argument d'un constructeur ou d'une fonction de conversion définie par l'utilisateur, une seule séquence de conversion standard est autorisée (sinon les conversions définies par l'utilisateur pourraient être effectivement chaînées). Lors de la conversion d'un type non-classe vers un autre type non-classe, seule une séquence de conversion standard est autorisée.
Une séquence de conversion standard se compose des éléments suivants, dans cet ordre :
- conversion lvalue-en-rvalue ,
- conversion tableau-en-pointeur , et
- conversion fonction-en-pointeur ;
|
3)
zéro ou une
conversion de pointeur de fonction
;
|
(depuis C++17) |
Une conversion définie par l'utilisateur consiste en zéro ou un appel de constructeur de conversion non-explicite à un seul argument ou de fonction de conversion non-explicite conversion function .
Une expression
e
est dite
implicitement convertible vers
T2
si et seulement si
T2
peut être
initialisé par copie
à partir de
e
, c'est-à-dire que la déclaration
T2 t
=
e
;
est bien formée (peut être compilée), pour un
t
temporaire inventé. Notez que ceci est différent de
l'initialisation directe
(
T2 t
(
e
)
), où les constructeurs explicites et les fonctions de conversion seraient également considérés.
Conversions contextuelles
|
Dans les contextes suivants, le type bool est attendu et la conversion implicite est effectuée si la déclaration bool t ( e ) ; est bien formée (c'est-à-dire qu'une fonction de conversion explicite telle que explicit T :: operator bool ( ) const ; est considérée). Une telle expression e est dite contextuellement convertie en bool .
|
(depuis C++11) |
Dans les contextes suivants, un type spécifique au contexte
T
est attendu, et l'expression
e
de type classe
E
n'est autorisée que si
|
(jusqu'à C++14) |
|
(depuis C++14) |
Une telle expression
e
est dite
implicitement convertie contextuellement
vers le type spécifié
T
.
Notez que les fonctions de conversion explicites ne sont pas considérées, même si elles sont prises en compte dans les conversions contextuelles vers
bool
.
(depuis C++11)
-
l'argument de l'
delete-expression
(
Test un type pointeur vers objet quelconque) ; -
expression constante intégrale
, où une classe littérale est utilisée (
Test un type intégral ou énumération non-scopée quelconque, la fonction de conversion définie par l'utilisateur sélectionnée doit être constexpr ) ; -
l'expression de contrôle de l'instruction
switch(Test un type intégral ou énumération quelconque).
#include <cassert> template<typename T> class zero_init { T val; public: zero_init() : val(static_cast<T>(0)) {} zero_init(T val) : val(val) {} operator T&() { return val; } operator T() const { return val; } }; int main() { zero_init<int> i; assert(i == 0); i = 7; assert(i == 7); switch (i) {} // erreur jusqu'à C++14 (plus d'une fonction de conversion) // OK depuis C++14 (les deux fonctions convertissent vers le même type int) switch (i + 0) {} // toujours correct (conversion implicite) }
Transformations de valeurs
Les transformations de valeur sont des conversions qui modifient la catégorie de valeur d'une expression. Elles se produisent chaque fois qu'une expression apparaît comme opérande d'un opérateur qui attend une expression d'une catégorie de valeur différente :
- Chaque fois qu'une glvalue apparaît comme opérande d'un opérateur qui nécessite une prvalue pour cet opérande, les conversions standard lvalue-to-rvalue , array-to-pointer , ou function-to-pointer sont appliquées pour convertir l'expression en une prvalue.
|
(since C++17) |
Conversion Lvalue en Rvalue
Une
lvalue
(jusqu'en C++11)
Une
glvalue
(depuis C++11)
de tout type non-fonction, non-tableau
T
peut être implicitement convertie en
une
rvalue
(jusqu'en C++11)
une
prvalue
(depuis C++11)
:
-
Si
Tn'est pas un type classe, le type de la rvalue (jusqu'en C++11) prvalue (depuis C++11) est la version non qualifiée cv deT. -
Sinon, le type de la
rvalue
(jusqu'en C++11)
prvalue
(depuis C++11)
est
T.
Si une conversion de lvalue en rvalue à partir d'un type incomplet est requise par un programme, ce programme est non conforme.
Étant donné l'objet auquel la lvalue (until C++11) glvalue (since C++11) fait référence comme obj :
|
(jusqu'à C++11) | ||||
|
(depuis C++11) |
Cette conversion modélise l'action de lecture d'une valeur depuis un emplacement mémoire vers un registre de processeur.
Conversion tableau-vers-pointeur
Un
lvalue
ou
rvalue
de type « tableau de
N
T
» ou « tableau de limite inconnue de
T
» peut être implicitement converti en un
prvalue
de type « pointeur vers
T
».
Si le tableau est un prvalue,
une matérialisation temporaire
se produit.
(depuis C++17)
Le pointeur résultant fait référence au premier élément du tableau (voir
Dégénérescence tableau-vers-pointeur
pour plus de détails).
Conversion fonction-vers-pointeur
Une lvalue de type fonction peut être implicitement convertie en un prvalue pointeur vers cette fonction . Cela ne s'applique pas aux fonctions membres non statiques car les lvalues qui se réfèrent aux fonctions membres non statiques n'existent pas.
Matérialisation temporaire
Une
prvalue
de tout type complet
Si
struct S { int m; }; int i = S().m; // member access expects glvalue as of C++17; // S() prvalue is converted to xvalue La matérialisation temporaire se produit dans les situations suivantes :
Notez que la matérialisation temporaire ne se produit pas lors de l'initialisation d'un objet à partir d'une prvalue du même type (par initialisation directe ou initialisation par copie ) : cet objet est initialisé directement à partir de l'initialiseur. Cela garantit "l'élision de copie garantie". |
(depuis C++17) |
Promotion intégrale
prvalues des petits types entiers (tels que char ) et des types énumération non délimités peuvent être convertis en prvalues de types entiers plus grands (tels que int ). En particulier, les opérateurs arithmétiques n'acceptent pas les types plus petits que int comme arguments, et les promotions entières sont automatiquement appliquées après la conversion lvalue-vers-rvalue, si applicable. Cette conversion préserve toujours la valeur.
Les conversions implicites suivantes dans cette section sont classées comme promotions intégrales .
Notez que pour un type source donné, le type de destination de la promotion intégrale est unique, et toutes les autres conversions ne sont pas des promotions. Par exemple, la résolution de surcharge choisit char -> int (promotion) plutôt que char -> short (conversion).
Promotion des types entiers
Une prvalue de type bool peut être convertie en une prvalue de type int , où false devient 0 et true devient 1 .
Pour une prvalue
val
de type intégral
T
sauf
bool
:
- val peut être converti en une prvalue de type int si int peut représenter toutes les valeurs du champ de bits ;
- sinon, val peut être converti en unsigned int si unsigned int peut représenter toutes les valeurs du champ de bits ;
- sinon, val peut être converti selon les règles spécifiées dans le point (3).
-
si
Test char8_t , (depuis C++20) char16_t , char32_t ou (depuis C++11) wchar_t , val peut être converti selon les règles spécifiées au point (3) ; -
sinon, si le
rang de conversion entier
de
Test inférieur au rang de int :
-
-
val
peut être converti en une prvalue de type
int
si
int
peut représenter toutes les valeurs de
T; - sinon, val peut être converti en une prvalue de type unsigned int .
-
val
peut être converti en une prvalue de type
int
si
int
peut représenter toutes les valeurs de
T
est l'un des types de caractères donnés),
val
peut être converti en une prvalue du premier des types suivants qui peut représenter toutes les valeurs de son type sous-jacent :
-
- int
- unsigned int
- long
- unsigned long
|
(depuis C++11) |
Promotion des types énumération
Une valeur prvalue d'un type d'énumération non-scopée enumeration dont le type sous-jacent n'est pas fixe peut être convertie en une valeur prvalue du premier type de la liste suivante capable de contenir toute leur plage de valeurs :
- int
- unsigned int
- long
- unsigned long
|
(depuis C++11) |
|
Une valeur prvalue d'un type énumération non scopée dont le type sous-jacent est fixe peut être convertie en son type sous-jacent. De plus, si le type sous-jacent est également soumis à la promotion entière, vers le type sous-jacent promu. La conversion vers le type sous-jacent non promu est meilleure pour les besoins de la résolution de surcharge . |
(since C++11) |
Promotion des nombres à virgule flottante
Une prvalue de type float peut être convertie en une prvalue de type double . La valeur ne change pas.
Cette conversion est appelée floating-point promotion .
Conversions numériques
Contrairement aux promotions, les conversions numériques peuvent modifier les valeurs, avec une perte de précision potentielle.
Conversions intégrales
Une prvalue d'un type entier ou d'un type d'énumération non délimitée peut être convertie en tout autre type entier. Si la conversion est listée sous les promotions entières, il s'agit d'une promotion et non d'une conversion.
-
Si le type de destination est non signé, la valeur résultante est la plus petite valeur non signée égale à la valeur source
modulo
2
n
où n est le nombre de bits utilisés pour représenter le type de destination.
-
- C'est-à-dire que, selon que le type de destination est plus large ou plus étroit, les entiers signés sont étendus par le signe [1] ou tronqués, et les entiers non signés sont étendus par des zéros ou tronqués respectivement.
-
Si le type de destination est signé, la valeur ne change pas si l'entier source peut être représenté dans le type de destination. Sinon, le résultat est
défini par l'implémentation
(jusqu'à C++20)
la valeur unique du type de destination égale à la valeur source modulo
2
n
où n est le nombre de bits utilisés pour représenter le type de destination (depuis C++20) (notez que ceci est différent du dépassement d'entier signé en arithmétique , qui est indéfini). - Si le type source est bool , la valeur false est convertie en zéro et la valeur true est convertie en la valeur un du type de destination (notez que si le type de destination est int , ceci est une promotion d'entier, pas une conversion d'entier).
- Si le type de destination est bool , ceci est une conversion booléenne (voir ci-dessous).
- ↑ Ceci s'applique uniquement si l'arithmétique est en complément à deux, ce qui n'est requis que pour les types entiers de largeur exacte . Notez cependant qu'actuellement, toutes les plateformes avec un compilateur C++ utilisent l'arithmétique en complément à deux.
Conversions en virgule flottante
|
Une prvalue d'un type à virgule flottante peut être convertie en une prvalue de tout autre type à virgule flottante. |
(jusqu'en C++23) |
|
Une prvalue d'un type à virgule flottante peut être convertie en une prvalue de tout autre type à virgule flottante ayant un rang de conversion à virgule flottante supérieur ou égal. Une prvalue d'un type à virgule flottante standard peut être convertie en une prvalue de tout autre type à virgule flottante standard.
|
(depuis C++23) |
Si la conversion est listée sous les promotions en virgule flottante, il s'agit d'une promotion et non d'une conversion.
- Si la valeur source peut être représentée exactement dans le type de destination, elle ne change pas.
- Si la valeur source est comprise entre deux valeurs représentables du type de destination, le résultat est l'une de ces deux valeurs (il est défini par l'implémentation laquelle, bien que si l'arithmétique IEEE est supportée, l'arrondi par défaut est au plus proche ).
- Sinon, le comportement est indéfini.
Conversions flottant–entier
Une prvalue de type virgule flottante peut être convertie en une prvalue de n'importe quel type entier. La partie fractionnaire est tronquée, c'est-à-dire que la partie fractionnaire est ignorée.
- Si la valeur tronquée ne peut pas être contenue dans le type de destination, le comportement est indéfini (même lorsque le type de destination est non signé, l'arithmétique modulaire ne s'applique pas).
- Si le type de destination est bool , il s'agit d'une conversion booléenne (voir ci-dessous ).
Une valeur prvalue de type entier ou énumération non délimitée peut être convertie en une valeur prvalue de tout type à virgule flottante. Le résultat est exact si possible.
- Si la valeur peut tenir dans le type de destination mais ne peut pas être représentée exactement, il est défini par l'implémentation si la valeur représentable la plus proche supérieure ou inférieure sera sélectionnée, bien que si l'arithmétique IEEE est supportée, l'arrondi par défaut au plus près .
- Si la valeur ne peut pas tenir dans le type de destination, le comportement est indéfini.
- Si le type source est bool , la valeur false est convertie en zéro, et la valeur true est convertie en un.
Conversions de pointeurs
Une constante de pointeur nul peut être convertie en n'importe quel type de pointeur, et le résultat est la valeur de pointeur nul de ce type. Une telle conversion (appelée conversion de pointeur nul ) est autorisée pour convertir vers un type qualifié cv comme une conversion unique, c'est-à-dire qu'elle n'est pas considérée comme une combinaison de conversions numériques et de qualifications.
Un
prvalue
pointeur vers n'importe quel type d'objet (éventuellement qualifié cv)
T
peut être converti en un prvalue pointeur vers
void
(identique qualification cv). Le pointeur résultant représente le même emplacement en mémoire que la valeur du pointeur original.
- Si le pointeur original est une valeur de pointeur nul, le résultat est une valeur de pointeur nul du type de destination.
Une prvalue
ptr
de type « pointeur vers (éventuellement qualifié-cv)
Derived
» peut être convertie en une prvalue de type « pointeur vers (éventuellement qualifié-cv)
Base
», où
Base
est une
classe de base
de
Derived
, et
Derived
est un type de classe
complet
. Si
Base
est inaccessible ou ambiguë, le programme est mal formé.
- Si ptr est une valeur de pointeur nul, le résultat est également une valeur de pointeur nul.
-
Sinon, si
Baseest une classe de base virtuelle deDerivedet que ptr ne pointe pas vers un objet dont le type est similaire àDerivedet qui se trouve dans sa durée de vie ou dans sa période de construction ou de destruction, le comportement est indéfini. - Sinon, le résultat est un pointeur vers le sous-objet de classe de base de l'objet de classe dérivée.
Conversions pointeur-vers-membre
Une constante de pointeur nul peut être convertie en n'importe quel type pointeur-vers-membre, et le résultat est la valeur de pointeur de membre nul de ce type. Une telle conversion (appelée conversion de pointeur de membre nul ) est autorisée pour convertir en un type cv-qualifié comme une conversion unique, c'est-à-dire qu'elle n'est pas considérée comme une combinaison de conversions numériques et de qualifications.
Une
prvalue
de type « pointeur vers membre de
Base
de type (éventuellement qualifié cv)
T
» peut être convertie en une prvalue de type « pointeur vers membre de
Derived
de type (identique qualifié cv)
T
», où
Base
est une classe de base de
Derived
, et
Derived
est un type de classe complet. Si
Base
est une base inaccessible, ambiguë ou virtuelle de
Derived
ou est une base d'une base virtuelle intermédiaire de
Derived
, le programme est mal formé.
-
Si
Derivedne contient pas le membre original et n'est pas une classe de base de la classe contenant le membre original, le comportement est indéfini. -
Sinon, le pointeur résultant peut être déréférencé avec un objet
Derived, et il accédera au membre dans le sous-objet de baseBasede cet objetDerived.
Conversions booléennes
Une prvalue de types entiers, à virgule flottante, énumération non délimitée, pointeur et pointeur-vers-membre peut être convertie en une prvalue de type bool .
La valeur zéro (pour les types entiers, à virgule flottante et les énumérations non délimités) ainsi que les valeurs de pointeur nul et de pointeur-vers-membre nul deviennent false . Toutes les autres valeurs deviennent true .
|
Dans le contexte d'une initialisation directe , un objet bool peut être initialisé à partir d'une prvalue de type std::nullptr_t , y compris nullptr . La valeur résultante est false . Cependant, cela n'est pas considéré comme une conversion implicite. |
(depuis C++11) |
Conversions de qualification
D'une manière générale :
-
Une
prvalue
de type pointeur vers un type
qualifié-cv
Tpeut être convertie en une prvalue pointeur vers le même typeTplus qualifié-cv (en d'autres termes, la constance et la volatilité peuvent être ajoutées). -
Une prvalue de type pointeur vers membre d'un type qualifié-cv
Tdans la classeXpeut être convertie en une prvalue pointeur vers membre d'un type plus qualifié-cvTdans la classeX.
La définition formelle de « qualification conversion » est donnée ci-dessous .
Types similaires
Informellement, deux types sont similaires si, en ignorant les qualifications cv de niveau supérieur :
- ils sont du même type ; ou
- ils sont tous deux des pointeurs, et les types pointés sont similaires ; ou
- ils sont tous deux des pointeurs vers un membre de la même classe, et les types des membres pointés sont similaires ; ou
- ils sont tous deux des tableaux et les types d'éléments du tableau sont similaires.
Par exemple :
- const int * const * et int ** sont similaires ;
- int ( * ) ( int * ) et int ( * ) ( const int * ) ne sont pas similaires ;
- const int ( * ) ( int * ) et int ( * ) ( int * ) ne sont pas similaires ;
- int ( * ) ( int * const ) et int ( * ) ( int * ) sont similaires (ils sont du même type) ;
- std:: pair < int , int > et std:: pair < const int , int > ne sont pas similaires.
Formellement, la similarité de types est définie en termes de décomposition de qualification.
Une
décomposition de qualification
d'un type
T
est une séquence de composants
cv_i
et
P_i
telle que
T
est «
cv_0 P_0 cv_1 P_1 ... cv_n−1 P_n−1 cv_n U
» pour un entier non négatif
n
, où
-
chaque
cv_iest un ensemble de const et volatile , et -
chaque
P_iest
-
- "pointeur vers",
-
"pointeur vers membre de la classe
C_ide type", - "tableau de N_i ", ou
- "tableau de limite inconnue de".
Si
P_i
désigne un tableau, les qualificateurs cv
cv_i+1
sur le type d'élément sont également pris comme les qualificateurs cv
cv_i
du tableau.
// T est « pointeur vers pointeur vers const int », il a 3 décompositions de qualification : // n = 0 -> cv_0 est vide, U est « pointeur vers pointeur vers const int » // n = 1 -> cv_0 est vide, P_0 est « pointeur vers », // cv_1 est vide, U est « pointeur vers const int » // n = 2 -> cv_0 est vide, P_0 est « pointeur vers », // cv_1 est vide, P_1 est « pointeur vers », // cv_2 est « const », U est « int » using T = const int**; // substituer l'un des types suivants à U donne l'une des décompositions : // U = U0 -> la décomposition avec n = 0 : U0 // U = U1 -> la décomposition avec n = 1 : pointeur vers [U1] // U = U2 -> la décomposition avec n = 2 : pointeur vers [pointeur vers [const U2]] using U2 = int; using U1 = const U2*; using U0 = U1*;
Deux types
T1
et
T2
sont
similaires
s'il existe une décomposition de qualification pour chacun d'eux, où toutes les conditions suivantes sont satisfaites pour les deux décompositions de qualification :
- Ils ont le même n .
-
Les types désignés par
Usont identiques. -
Les composants correspondants
P_isont identiques ou l'un est « tableau de N_i » et l'autre est « tableau de limite inconnue de » (depuis C++20) pour tous les i .
// la décomposition de qualification avec n = 2 : // pointeur vers [pointeur volatile vers [const int]] using T1 = const int* volatile *; // la décomposition de qualification avec n = 2 : // pointeur const vers [pointeur vers [int]] using T2 = int** const; // Pour les deux décompositions de qualification ci-dessus // bien que cv_0, cv_1 et cv_2 soient tous différents, // ils ont le même n, U, P_0 et P_1, // par conséquent les types T1 et T2 sont similaires.
Combinaison des qualifications cv
Dans la description ci-dessous, la décomposition de qualification la plus longue du type
Tn
est notée
Dn
, et ses composantes sont notées
cvn_i
et
Pn_i
.
|
Une expression prvalue de type
Le
type combiné de qualifications
de deux types
|
(jusqu'en C++20) |
|
Le
type combiné de qualifications
de deux types
Une prvalue de type
|
(depuis C++20) |
// décomposition de qualification la plus longue de T1 (n = 2) : // pointeur vers [pointeur vers [char]] using T1 = char**; // décomposition de qualification la plus longue de T2 (n = 2) : // pointeur vers [pointeur vers [const char]] using T2 = const char**; // Détermination des composants cv3_i et T_i de D3 (n = 2) : // cv3_1 = vide (union de cv1_1 vide et cv2_1 vide) // cv3_2 = "const" (union de cv1_2 vide et "const" cv2_2) // P3_0 = "pointeur vers" (aucun tableau de taille inconnue, utiliser P1_0) // P3_1 = "pointeur vers" (aucun tableau de taille inconnue, utiliser P1_1) // Tous les composants sauf cv_2 sont identiques, cv3_2 est différent de cv1_2, // donc ajouter "const" à cv3_k pour chaque k dans [1, 2) : cv3_1 devient "const". // T3 est "pointeur vers pointeur const vers const char", c'est-à-dire const char* const *. using T3 = /* le type combiné par qualification de T1 et T2 */; int main() { const char c = 'c'; char* pc; T1 ppc = &pc; T2 pcc = ppc; // Erreur : T3 n'est pas identique à T2 sans qualification cv, // pas de conversion implicite. *pcc = &c; *pc = 'C'; // Si l'assignation erronée ci-dessus est autorisée, // l'objet const "c" pourrait être modifié. }
Notez que dans le langage de programmation C, const / volatile ne peut être ajouté qu'au premier niveau :
char** p = 0; char * const* p1 = p; // OK en C et C++ const char* const * p2 = p; // erreur en C, OK en C++
Conversions de pointeurs de fonction
void (*p)(); void (**pp)() noexcept = &p; // error: cannot convert to pointer to noexcept function struct S { typedef void (*p)(); operator p(); }; void (*q)() noexcept = S(); // error: cannot convert to pointer to noexcept function |
(depuis C++17) |
Le problème du booléen sécurisé
Jusqu'à C++11, concevoir une classe qui devait être utilisable dans des contextes booléens (par exemple if ( obj ) { ... } ) posait un problème : étant donné une fonction de conversion définie par l'utilisateur, telle que T :: operator bool ( ) const ; , la séquence de conversion implicite autorisait une séquence de conversion standard supplémentaire après cet appel de fonction, ce qui signifie que le bool résultant pouvait être converti en int , permettant du code tel que obj << 1 ; ou int i = obj ; .
Une solution précoce pour cela peut être observée dans std::basic_ios , qui définit initialement operator void * , de sorte que le code tel que if ( std:: cin ) { ... } compile car void * est convertible en bool , mais int n = std:: cout ; ne compile pas car void * n'est pas convertible en int . Cela permet toujours à du code absurde tel que delete std:: cout ; de compiler.
De nombreuses bibliothèques tierces pré-C++11 étaient conçues avec une solution plus élaborée, connue sous le nom d' idiome Safe Bool . std::basic_ios permettait également cet idiome via LWG issue 468 , et operator void * a été remplacé (voir les notes ).
Depuis C++11, la conversion explicite vers bool peut également être utilisée pour résoudre le problème du safe bool.
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 170 | C++98 |
le comportement des conversions pointeur-vers-membre était ambigu
si la classe dérivée ne possède pas le membre d'origine |
clarifié |
| CWG 172 | C++98 | le type énumération était promu en fonction de son type sous-jacent | en fonction de sa plage de valeurs à la place |
|
CWG 330
( N4261 ) |
C++98 |
la conversion de
double
*
const
(
*
p
)
[
3
]
vers double const * const ( * p ) [ 3 ] était invalide |
rendue valide |
| CWG 519 | C++98 |
les valeurs de pointeur nul n'étaient pas garanties d'être
préservées lors de la conversion vers un autre type de pointeur |
toujours préservées |
| CWG 616 | C++98 |
le comportement de la conversion lvalue en rvalue de
tout objet non initialisé et des objets pointeur avec des valeurs invalides était toujours indéfini |
indéterminé
unsigned
char
est autorisé ; l'utilisation de pointeurs invalides est définie par l'implémentation |
| CWG 685 | C++98 |
le type sous-jacent d'un type énumération n'était
pas priorisé dans la promotion intégrale s'il est fixe |
priorisé |
| CWG 707 | C++98 |
la conversion d'entier en virgule flottante
avait un comportement défini dans tous les cas |
le comportement est indéfini si
la valeur convertie est hors de la plage de destination |
| CWG 1423 | C++11 |
std::nullptr_t
était convertible en
bool
dans l'initialisation directe et par copie |
initialisation directe uniquement |
| CWG 1773 | C++11 |
une expression de nom qui apparaît dans une expression potentiellement évaluée
telle que l'objet nommé n'est pas odr-utilisé pourrait quand même être évaluée lors d'une conversion lvalue-vers-rvalue |
non évalué |
| CWG 1781 | C++11 |
std::nullptr_t
vers
bool
était considéré comme une conversion
implicite même s'il n'est valide que pour l'initialisation directe |
n'est plus considéré
comme une conversion implicite |
| CWG 1787 | C++98 |
le comportement de la lecture d'un
unsigned char indéterminé mis en cache dans un registre était indéfini |
rendu bien défini |
| CWG 1981 | C++11 | conversions contextuelles considérées comme des fonctions de conversion explicites | non considéré |
| CWG 2140 | C++11 |
il n'était pas clair si les conversions lvalue-vers-rvalue à partir
std::nullptr_t lvalues récupèrent ces lvalues en mémoire |
non récupérées |
| CWG 2310 | C++98 |
pour les conversions pointeur de dérivé vers base et
les conversions pointeur-vers-membre de base vers dérivé, le type de classe dérivée pouvait être incomplet |
doit être complet |
| CWG 2484 | C++20 |
char8_t
et
char16_t
avaient des stratégies de promotion
entière différentes, mais ils peuvent les accommoder toutes deux |
char8_t
devrait être promu
de la même manière que char16_t |
| CWG 2485 | C++98 | les promotions entières impliquant des champs de bits n'étaient pas spécifiées correctement | a amélioré la spécification |
| CWG 2813 | C++23 |
la matérialisation temporaire se produirait lorsqu'une fonction membre
à objet explicite d'une prvalue de classe est invoquée |
ne se produira pas
dans ce cas |
| CWG 2861 | C++98 |
un pointeur vers un objet inaccessible par le type pouvait être
converti en un pointeur vers un sous-objet de classe de base |
le comportement est
indéfini dans ce cas |
| CWG 2879 | C++17 |
la conversion de matérialisation temporaire était appliquée sur une prvalue
comme opérande d'un opérateur qui attend une glvalue |
non appliquée dans certains cas |
| CWG 2899 | C++98 |
les conversions lvalue-en-rvalue pouvaient être appliquées aux lvalues
désignant des objets avec des représentations de valeur invalides |
le comportement est
indéfini dans ce cas |
| CWG 2901 | C++98 |
le résultat de la conversion lvalue-vers-rvalue d'une
unsigned
int
lvalue se référant à un objet int avec la valeur - 1 était ambigu |
clarifié |
Voir aussi
-
const_cast -
static_cast -
dynamic_cast -
reinterpret_cast - conversion explicite
- conversion définie par l'utilisateur
|
Documentation C
pour
Conversions implicites
|