Implicit conversions
Неявные преобразования выполняются всякий раз, когда выражение некоторого типа
T1
используется в контексте, который не принимает этот тип, но принимает некоторый другой тип
T2
; в частности:
-
когда выражение используется в качестве аргумента при вызове функции, объявленной с параметром типа
T2; -
когда выражение используется в качестве операнда с оператором, который ожидает тип
T2; -
при инициализации нового объекта типа
T2, включая операторreturnв функции, возвращающей типT2; -
когда выражение используется в операторе
switch
(
T2является целочисленным типом); -
когда выражение используется в операторе
if
или цикле (
T2является типом bool ).
Программа является корректной (компилируется) только в том случае, если существует однозначная
неявная последовательность преобразования
из
T1
в
T2
.
Если существует несколько перегрузок вызываемой функции или оператора, после построения последовательности неявных преобразований из
T1
в каждый доступный
T2
,
правила разрешения перегрузки
определяют, какая перегрузка будет скомпилирована.
Примечание: в арифметических выражениях целевой тип для неявных преобразований операндов бинарных операторов определяется отдельным набором правил: usual arithmetic conversions .
Содержание |
Порядок преобразований
Неявная последовательность преобразования состоит из следующего, в таком порядке:
При рассмотрении аргумента конструктора или пользовательской функции преобразования допускается только одна стандартная последовательность преобразований (в противном случае пользовательские преобразования могли бы эффективно объединяться в цепочку). При преобразовании из одного неклассового типа в другой неклассовый тип допускается только стандартная последовательность преобразований.
Стандартная последовательность преобразований состоит из следующего, в таком порядке:
- lvalue-to-rvalue conversion ,
- array-to-pointer conversion , и
- function-to-pointer conversion ;
|
3)
ноль или одно
function pointer conversion
;
|
(since C++17) |
Пользовательское преобразование состоит из нуля или одного неявного одноаргументного converting constructor или неявного conversion function вызова.
Выражение
e
называется
неявно преобразуемым в
T2
тогда и только тогда, когда
T2
может быть
копически инициализирован
из
e
, то есть объявление
T2 t
=
e
;
является корректным (может быть скомпилировано) для некоторой введённой временной переменной
t
. Заметьте, что это отличается от
прямой инициализации
(
T2 t
(
e
)
), где дополнительно рассматриваются явные конструкторы и функции преобразования.
Контекстные преобразования
|
В следующих контекстах ожидается тип bool и выполняется неявное преобразование, если объявление bool t ( e ) ; является корректным (то есть, явная функция преобразования, такая как explicit T :: operator bool ( ) const ; рассматривается). Такое выражение e называется контекстно преобразованным в bool .
|
(since C++11) |
В следующих контекстах ожидается контекстно-зависимый тип
T
, и выражение
e
типа класса
E
разрешено только если
|
(до C++14) |
|
(начиная с C++14) |
Такое выражение
e
называется
контекстно неявно преобразуемым
в указанный тип
T
.
Заметьте, что явные функции преобразования не рассматриваются, даже если они учитываются при контекстных преобразованиях к
bool
.
(начиная с C++11)
-
аргумент
delete-expression
(
T— любой тип указателя на объект); -
integral constant expression
, где используется литеральный класс (
T— любой целочисленный тип или тип неограниченного перечисления, выбранная пользовательская функция преобразования должна быть constexpr ); -
управляющее выражение оператора
switch(T— любой целочисленный тип или тип перечисления).
#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) {} // ошибка до C++14 (более одной функции преобразования) // OK с C++14 (обе функции преобразуют к одному типу int) switch (i + 0) {} // всегда работает (неявное преобразование) }
Преобразования значений
Трансформации значений — это преобразования, которые изменяют категорию значения выражения. Они происходят всякий раз, когда выражение появляется в качестве операнда оператора, который ожидает выражение другой категории значения:
- Всякий раз, когда glvalue появляется в качестве операнда оператора, требующего prvalue для этого операнда, применяются стандартные преобразования lvalue-to-rvalue , array-to-pointer или function-to-pointer для преобразования выражения в prvalue.
|
(начиная с C++17) |
Преобразование lvalue в rvalue
Lvalue
lvalue
(до C++11)
Glvalue
glvalue
(начиная с C++11)
любого не-функционального, не-массивного типа
T
может быть неявно преобразовано в
rvalue
rvalue
(до C++11)
prvalue
prvalue
(начиная с C++11)
:
-
Если
Tне является типом класса, тип rvalue (до C++11) prvalue (начиная с C++11) является версиейTбез cv-квалификаторов. -
В противном случае тип
rvalue
(до C++11)
prvalue
(начиная с C++11)
равен
T.
Если в программе требуется преобразование lvalue в rvalue для неполного типа , такая программа является некорректной.
Учитывая объект, на который ссылается lvalue (until C++11) glvalue (since C++11) , как obj :
|
(до C++11) | ||||
|
(начиная с C++11) |
Это преобразование моделирует операцию чтения значения из ячейки памяти в регистр процессора.
Преобразование массива в указатель
lvalue
или
rvalue
типа "массив из
N
T
" или "массив неизвестной границы из
T
" может быть неявно преобразован в
prvalue
типа "указатель на
T
".
Если массив является prvalue, происходит
материализация временного объекта
.
(начиная с C++17)
Результирующий указатель ссылается на первый элемент массива (см.
Array-to-pointer decay
для подробностей).
Преобразование функции в указатель
Выражение lvalue функционального типа может быть неявно преобразовано в prvalue указатель на эту функцию . Это не применимо к нестатическим функциям-членам, поскольку lvalue, ссылающиеся на нестатические функции-члены, не существуют.
Материализация временных объектов
Любой
prvalue
полного типа
Если
struct S { int m; }; int i = S().m; // member access expects glvalue as of C++17; // S() prvalue is converted to xvalue Материализация временных объектов происходит в следующих ситуациях:
Обратите внимание, что материализация временных объектов не происходит при инициализации объекта из prvalue того же типа (через прямую инициализацию или копирующую инициализацию ): такой объект инициализируется напрямую из инициализатора. Это обеспечивает «гарантированное устранение копирования». |
(начиная с C++17) |
Целочисленные повышения
prvalues малых целочисленных типов (таких как char ) и типов неограниченных перечислений могут быть преобразованы в prvalues более крупных целочисленных типов (таких как int ). В частности, арифметические операторы не принимают типы меньше int в качестве аргументов, и целочисленные повышения автоматически применяются после преобразования lvalue-to-rvalue, если применимо. Это преобразование всегда сохраняет значение.
Следующие неявные преобразования в этом разделе классифицируются как целочисленные повышения .
Обратите внимание, что для заданного исходного типа тип назначения целочисленного повышения уникален, и все остальные преобразования не являются повышениями. Например, разрешение перегрузки выбирает char -> int (повышение) вместо char -> short (преобразование).
Продвижение из целочисленных типов
Значение prvalue типа bool может быть преобразовано в значение prvalue типа int , при этом false становится 0 , а true становится 1 .
Для prvalue
val
целочисленного типа
T
за исключением
bool
:
- val может быть преобразовано в prvalue типа int если int может представить все значения битового поля;
- иначе, val может быть преобразовано в unsigned int если unsigned int может представить все значения битового поля;
- иначе, val может быть преобразовано согласно правилам, указанным в пункте (3).
-
если
Tявляется char8_t , (начиная с C++20) char16_t , char32_t или (начиная с C++11) wchar_t , val может быть преобразован согласно правилам, указанным в пункте (3); -
в противном случае, если
ранг целочисленного преобразования
для
Tниже ранга int :
-
-
val
может быть преобразован в prvalue типа
int
, если
int
может представить все значения типа
T; - иначе, val может быть преобразован в prvalue типа unsigned int .
-
val
может быть преобразован в prvalue типа
int
, если
int
может представить все значения типа
T
является одним из указанных символьных типов),
val
может быть преобразовано в prvalue первого из следующих типов, который может представить все значения его базового типа:
-
- int
- unsigned int
- long
- unsigned long
|
(начиная с C++11) |
Продвижение из типов перечисления
Правостое значение неограниченного перечисления с неустановленным базовым типом может быть преобразовано в правостое значение первого типа из следующего списка, способного вместить весь диапазон их значений:
- int
- unsigned int
- long
- unsigned long
|
(начиная с C++11) |
|
Правостое значение неограниченного перечисления с фиксированным базовым типом может быть преобразовано в его базовый тип. Более того, если базовый тип также подвергается целочисленному повышению, то в повышенный базовый тип. Для целей разрешения перегрузки преобразование в неповышенный базовый тип является предпочтительным. |
(since C++11) |
Продвижение чисел с плавающей точкой
Значение категории prvalue типа float может быть преобразовано в значение категории prvalue типа double . Значение при этом не изменяется.
Это преобразование называется floating-point promotion .
Числовые преобразования
В отличие от повышений, числовые преобразования могут изменять значения с потенциальной потерей точности.
Целочисленные преобразования
prvalue целочисленного типа или типа неограниченного перечисления может быть преобразован в любой другой целочисленный тип. Если преобразование указано в рамках целочисленных повышений, это является повышением, а не преобразованием.
-
Если тип назначения беззнаковый, результирующее значение является наименьшим беззнаковым значением, равным исходному значению
по модулю
2
n
где n — количество битов, используемых для представления типа назначения.
-
- То есть, в зависимости от того, является ли целевой тип шире или уже, знаковые целые числа знаково расширяются [1] или усекаются, а беззнаковые целые числа соответственно либо дополняются нулями, либо усекаются.
-
Если целевой тип является знаковым, значение не изменяется, если исходное целое число может быть представлено в целевом типе. В противном случае результат
определяется реализацией
(до C++20)
уникальным значением целевого типа, равным исходному значению по модулю
2
n
где n — количество битов, используемых для представления целевого типа (начиная с C++20) (обратите внимание, что это отличается от переполнения знаковой целочисленной арифметики , которое является неопределённым поведением). - Если исходный тип — bool , значение false преобразуется в ноль, а значение true преобразуется в единицу целевого типа (обратите внимание, что если целевой тип — int , это является целочисленным продвижением, а не целочисленным преобразованием).
- Если целевой тип — bool , это является булевым преобразованием (см. ниже).
- ↑ Это применимо только в случае, если арифметика является дополнительным кодом, что требуется только для точных целочисленных типов . Однако обратите внимание, что в настоящее время все платформы с компилятором C++ используют арифметику дополнительного кода.
Преобразования чисел с плавающей запятой
|
Значение категории prvalue типа с плавающей запятой может быть преобразовано в значение категории prvalue любого другого типа с плавающей запятой. |
(до C++23) |
|
Значение категории prvalue типа с плавающей запятой может быть преобразовано в значение категории prvalue любого другого типа с плавающей запятой с большим или равным рангом преобразования с плавающей запятой . Значение категории prvalue стандартного типа с плавающей запятой может быть преобразовано в значение категории prvalue любого другого стандартного типа с плавающей запятой.
|
(начиная с C++23) |
Если преобразование указано в разделе плавающих промоушенов, это является промоушеном, а не преобразованием.
- Если исходное значение может быть точно представлено в целевом типе, оно не изменяется.
- Если исходное значение находится между двумя представимыми значениями целевого типа, результатом будет одно из этих двух значений (определяется реализацией, какое именно, хотя при поддержке арифметики IEEE округление по умолчанию к ближайшему ).
- В противном случае поведение не определено.
Преобразования плавающих–целочисленные
Значение категории prvalue с плавающей точкой может быть преобразовано в значение категории prvalue любого целочисленного типа. Дробная часть усекается, то есть отбрасывается.
- Если усечённое значение не может быть помещено в целевой тип, поведение не определено (даже если целевой тип беззнаковый, модульная арифметика не применяется).
- Если целевой тип bool , это булево преобразование (см. ниже ).
Правэлью целочисленного типа или типа неограниченного перечисления может быть преобразовано в правэлью любого типа с плавающей точкой. Результат является точным, если это возможно.
- Если значение может поместиться в целевой тип, но не может быть представлено точно, определяется реализацией, будет выбрано ближайшее большее или ближайшее меньшее представимое значение, хотя при поддержке арифметики IEEE округление по умолчанию к ближайшему .
- Если значение не может поместиться в целевой тип, поведение не определено.
- Если исходный тип bool , значение false преобразуется в ноль, а значение true преобразуется в единицу.
Преобразования указателей
Нулевой указатель-константа null pointer constant может быть преобразован в любой тип указателя, и результатом будет нулевое значение указателя этого типа. Такое преобразование (известное как null pointer conversion ) допускается для преобразования в cv-квалифицированный тип как единое преобразование, то есть оно не считается комбинацией числового и квалифицирующего преобразований.
Указатель-правостороннее значение на любой (опционально cv-квалифицированный) тип объекта
T
может быть преобразован в указатель-правостороннее значение на (идентично cv-квалифицированный)
void
. Результирующий указатель представляет ту же позицию в памяти, что и исходное значение указателя.
- Если исходный указатель является нулевым указателем, результатом будет нулевой указатель целевого типа.
Правое значение
ptr
типа «указатель на (возможно, cv-квалифицированный)
Derived
» может быть преобразовано в правое значение типа «указатель на (возможно, cv-квалифицированный)
Base
», где
Base
является
базовым классом
для
Derived
, а
Derived
представляет собой
полный
тип класса. Если
Base
недоступен или неоднозначен, программа является некорректной.
- Если ptr является нулевым указателем, результат также будет нулевым указателем.
-
В противном случае, если
Baseявляется виртуальным базовым классом дляDerivedи ptr не указывает на объект, тип которого подобенDerivedи который находится в пределах своего времени жизни или в периоде своего конструирования или разрушения, поведение не определено. - В противном случае результат представляет собой указатель на подобъект базового класса объекта производного класса.
Преобразования указателей на члены
Нулевой указатель-константа null pointer constant может быть преобразован в любой тип указателя-на-член, и результатом будет нулевое значение указателя-на-член этого типа. Такое преобразование (известное как null member pointer conversion ) допускает преобразование в cv-квалифицированный тип как единое преобразование, то есть не считается комбинацией числового и квалифицирующего преобразований.
Значение категории
prvalue
типа «указатель на член класса
Base
типа (возможно cv-квалифицированный)
T
» может быть преобразовано в значение категории prvalue типа «указатель на член класса
Derived
типа (идентично cv-квалифицированный)
T
», где
Base
является базовым классом для
Derived
, и
Derived
является полным типом класса. Если
Base
является недоступным, неоднозначным или виртуальным базовым классом для
Derived
или является базовым классом некоторого промежуточного виртуального базового класса для
Derived
, программа является некорректной.
-
Если
Derivedне содержит исходный член и не является базовым классом класса, содержащего исходный член, поведение не определено. -
В противном случае, полученный указатель может быть разыменован с объектом
Derived, и он будет обращаться к члену внутри базового подобъектаBaseэтого объектаDerived.
Логические преобразования
Значение категории prvalue целочисленного, вещественного, неперечислимого типа, а также указателя и указателя на член класса может быть преобразовано в значение категории prvalue типа bool .
Значение ноль (для целочисленных, плавающих типов и неограниченных перечислений), нулевой указатель и нулевой указатель на члены становятся false . Все остальные значения становятся true .
|
В контексте прямой инициализации , объект типа bool может быть инициализирован из prvalue типа std::nullptr_t , включая nullptr . Результирующее значение равно false . Однако это не считается неявным преобразованием. |
(начиная с C++11) |
Преобразования квалификаторов
Вообще говоря:
-
Значение категории prvalue типа указатель на
prvalue
cv-квалифицированный
тип
Tможет быть преобразовано в prvalue указатель на более cv-квалифицированный тот же типT(другими словами, константность и волатильность могут быть добавлены). -
Значение категории prvalue типа указатель на член cv-квалифицированного типа
Tв классеXможет быть преобразовано в prvalue указатель на член более cv-квалифицированного типаTв классеX.
Формальное определение «квалификационного преобразования» приведено ниже .
Похожие типы
Неформально, два типа являются подобными если, игнорируя cv-квалификаторы верхнего уровня:
- они являются одним и тем же типом; или
- они оба являются указателями, и указываемые типы подобны; или
- они оба являются указателями на члены одного класса, и типы указываемых членов подобны; или
- они оба являются массивами и типы элементов массивов подобны.
Например:
- const int * const * и int ** являются схожими;
- int ( * ) ( int * ) и int ( * ) ( const int * ) не являются схожими;
- const int ( * ) ( int * ) и int ( * ) ( int * ) не являются схожими;
- int ( * ) ( int * const ) и int ( * ) ( int * ) являются схожими (это один и тот же тип);
- std:: pair < int , int > и std:: pair < const int , int > не являются схожими.
Формально, сходство типов определяется через квалификационную декомпозицию.
Квалификационная декомпозиция
типа
T
представляет собой последовательность компонентов
cv_i
и
P_i
такую, что
T
имеет вид «
cv_0 P_0 cv_1 P_1 ... cv_n−1 P_n−1 cv_n U
» для неотрицательного
n
, где
-
каждый
cv_iпредставляет собой набор const и volatile , и -
каждый
P_iявляется
-
- "указатель на",
-
"указатель на член класса
C_iтипа", - "массив из N_i ", или
- "массив неизвестной границы".
Если
P_i
обозначает массив, cv-квалификаторы
cv_i+1
типа элемента также принимаются в качестве cv-квалификаторов
cv_i
массива.
// T - это "указатель на указатель на const int", имеет 3 квалификационных декомпозиции: // n = 0 -> cv_0 пусто, U - "указатель на указатель на const int" // n = 1 -> cv_0 пусто, P_0 - "указатель на", // cv_1 пусто, U - "указатель на const int" // n = 2 -> cv_0 пусто, P_0 - "указатель на", // cv_1 пусто, P_1 - "указатель на", // cv_2 - "const", U - "int" using T = const int**; // подстановка любого из следующих типов в U дает одну из декомпозиций: // U = U0 -> декомпозиция с n = 0: U0 // U = U1 -> декомпозиция с n = 1: указатель на [U1] // U = U2 -> декомпозиция с n = 2: указатель на [указатель на [const U2]] using U2 = int; using U1 = const U2*; using U0 = U1*;
Два типа
T1
и
T2
называются
подобными
, если существует квалификационная декомпозиция для каждого из них, при которой для двух квалификационных декомпозиций выполняются все следующие условия:
- Они имеют одинаковое n .
-
Типы, обозначаемые
U, одинаковы. -
Соответствующие компоненты
P_iодинаковы или один является «массивом N_i », а другой — «массивом неизвестной границы» (начиная с C++20) для всех i .
// квалификационная декомпозиция с n = 2: // указатель на [volatile указатель на [const int]] using T1 = const int* volatile *; // квалификационная декомпозиция с n = 2: // const указатель на [указатель на [int]] using T2 = int** const; // Для двух приведенных выше квалификационных декомпозиций // хотя cv_0, cv_1 и cv_2 все различны, // они имеют одинаковые n, U, P_0 и P_1, // следовательно, типы T1 и T2 являются подобными.
Комбинирование cv-квалификаторов
В приведенном ниже описании самая длинная квалификационная декомпозиция типа
Tn
обозначается как
Dn
, а её компоненты обозначаются как
cvn_i
и
Pn_i
.
|
Выражение-правостоечное значение типа
Тип с объединёнными квалификаторами
двух типов
|
(до C++20) |
|
Тип с объединёнными квалификаторами
двух типов
Правостоечное значение типа
|
(начиная с C++20) |
// самая длинная квалификационная декомпозиция T1 (n = 2): // указатель на [указатель на [char]] using T1 = char**; // самая длинная квалификационная декомпозиция T2 (n = 2): // указатель на [указатель на [const char]] using T2 = const char**; // Определение компонентов cv3_i и T_i для D3 (n = 2): // cv3_1 = пусто (объединение пустого cv1_1 и пустого cv2_1) // cv3_2 = "const" (объединение пустого cv1_2 и "const" cv2_2) // P3_0 = "указатель на" (нет массива неизвестной границы, используем P1_0) // P3_1 = "указатель на" (нет массива неизвестной границы, используем P1_1) // Все компоненты кроме cv_2 одинаковы, cv3_2 отличается от cv1_2, // поэтому добавляем "const" к cv3_k для каждого k в [1, 2): cv3_1 становится "const". // T3 - это "указатель на const указатель на const char", т.е. const char* const *. using T3 = /* тип с объединенными квалификациями T1 и T2 */; int main() { const char c = 'c'; char* pc; T1 ppc = &pc; T2 pcc = ppc; // Ошибка: T3 не совпадает с T2 без cv-квалификаторов, // неявное преобразование невозможно. *pcc = &c; *pc = 'C'; // Если ошибочное присваивание выше разрешено, // const-объект "c" может быть изменен. }
Обратите внимание, что в языке программирования C const / volatile могут быть добавлены только на первом уровне:
char** p = 0; char * const* p1 = p; // OK в C и C++ const char* const * p2 = p; // ошибка в C, OK в C++
Преобразования указателей на функции
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 |
(начиная с C++17) |
Проблема безопасного bool
До C++11 проектирование класса, который должен быть пригоден для использования в булевых контекстах (например, if ( obj ) { ... } ), представляло проблему: при наличии пользовательской функции преобразования, такой как T :: operator bool ( ) const ; , неявная последовательность преобразования допускала одну дополнительную стандартную последовательность преобразования после этого вызова функции, что означает, что результирующий bool мог быть преобразован в int , позволяя такой код, как obj << 1 ; или int i = obj ; .
Одно из ранних решений для этого можно увидеть в std::basic_ios , который изначально определяет operator void * , так что код вида if ( std:: cin ) { ... } компилируется, поскольку void * преобразуется в bool , но int n = std:: cout ; не компилируется, так как void * не преобразуется в int . Это всё ещё позволяет компилироваться бессмысленному коду, такому как delete std:: cout ; .
Многие сторонние библиотеки до C++11 были разработаны с более сложным решением, известным как Safe Bool idiom . std::basic_ios также позволял использовать этот идиом через LWG issue 468 , и operator void * был заменен (см. примечания ).
Начиная с C++11, явное преобразование в bool также может использоваться для решения проблемы безопасного bool.
Отчеты о дефектах
Следующие отчеты об изменениях в поведении, являющиеся дефектными, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применяется к | Поведение как опубликовано | Корректное поведение |
|---|---|---|---|
| CWG 170 | C++98 |
поведение преобразований указателей на члены было неясным
если производный класс не имеет исходного члена |
прояснено |
| CWG 172 | C++98 | тип перечисления повышался на основе его базового типа | на основе его диапазона значений вместо этого |
|
CWG 330
( N4261 ) |
C++98 |
преобразование из
double
*
const
(
*
p
)
[
3
]
в double const * const ( * p ) [ 3 ] было недопустимым |
сделано допустимым |
| CWG 519 | C++98 |
нулевые значения указателей не гарантировали сохранения
при преобразовании к другому типу указателя |
всегда сохраняются |
| CWG 616 | C++98 |
поведение преобразования lvalue в rvalue для
любого неинициализированного объекта и объектов-указателей с недопустимыми значениями всегда было неопределенным |
неопределенное значение
unsigned
char
разрешено; использование недопустимых указателей определяется реализацией |
| CWG 685 | C++98 |
базовый тип перечисления не
учитывался в приоритете при целочисленном повышении, если он фиксирован |
учитывается |
| CWG 707 | C++98 |
преобразование целого числа в число с плавающей точкой
имело определенное поведение во всех случаях |
поведение становится неопределенным, если
преобразуемое значение находится вне диапазона приемника |
| CWG 1423 | C++11 |
std::nullptr_t
был преобразуем в
bool
как при прямой, так и при копирующей инициализации |
только прямая инициализация |
| CWG 1773 | C++11 |
выражение имени, которое появляется в потенциально вычисляемом
выражении, такое что именованный объект не является odr-используемым, может всё равно вычисляться во время преобразования lvalue-to-rvalue |
не вычисляется |
| CWG 1781 | C++11 |
std::nullptr_t
в
bool
считалось неявным
преобразованием, хотя оно допустимо только для прямой инициализации |
больше не считается
неявным преобразованием |
| CWG 1787 | C++98 |
поведение чтения из неопределенного
unsigned char кэшированного в регистре было неопределенным |
сделано определенным |
| CWG 1981 | C++11 | контекстуальные преобразования рассматривали явные функции преобразования | не рассматривалось |
| CWG 2140 | C++11 |
было неясно, выполняют ли преобразования lvalue-to-rvalue из
std::nullptr_t lvalues загрузку этих lvalues из памяти |
не загружаются |
| CWG 2310 | C++98 |
для преобразований указателей из производного в базовый класс и
преобразований указателей на члены из базового в производный класс, тип производного класса мог быть неполным |
должен быть полным |
| CWG 2484 | C++20 |
char8_t
и
char16_t
имели разные стратегии
целочисленного продвижения, но они могут подходить для обоих |
char8_t
должен продвигаться
таким же образом, как char16_t |
| CWG 2485 | C++98 | целочисленные повышения, связанные с битовыми полями, были плохо специфицированы | улучшена спецификация |
| CWG 2813 | C++23 |
материализация временного объекта происходила бы при вызове
явной объектной функции-члена prvalue класса |
не будет происходить
в этом случае |
| CWG 2861 | C++98 |
указатель на объект с недоступным типом может быть
преобразован в указатель на подобъект базового класса |
поведение в этом случае
не определено |
| CWG 2879 | C++17 |
временная материализационная конверсия применялась к prvalue
как операнду оператора, который ожидает glvalue |
не применялась в некоторых случаях |
| CWG 2899 | C++98 |
Преобразования lvalue-to-rvalue могли применяться к lvalues,
обозначающим объекты с недопустимыми представлениями значений |
Поведение в этом случае
не определено |
| CWG 2901 | C++98 |
результат преобразования lvalue-to-rvalue для
unsigned
int
lvalue, ссылающегося на объект int со значением - 1 был неясен |
прояснено |
Смотрите также
-
const_cast -
static_cast -
dynamic_cast -
reinterpret_cast - явное приведение
- пользовательское преобразование
|
Документация C
для
Неявные преобразования
|