Пространства имён
Варианты
Действия

Неявные преобразования

Материал из cppreference.com
< cpp‎ | language
 
 
Язык С++
Общие темы
Управление потоком
Операторы условного выполнения
if
Операторы итерации (циклы)
Операторы перехода
Функции
Объявление функции
Выражение лямбда-функции
Спецификатор inline
Спецификации динамических исключений (до C++17*)
Спецификатор noexcept (C++11)
Исключения
Пространства имён
Типы
Спецификаторы
decltype (C++11)
auto (C++11)
alignas (C++11)
Спецификаторы длительности хранения
Инициализация
Выражения
Альтернативные представления
Литералы
Логические - Целочисленные - С плавающей запятой
Символьные - Строковые - nullptr (C++11)
Определяемые пользователем (C++11)
Утилиты
Атрибуты (C++11)
Types
Объявление typedef
Объявление псевдонима типа (C++11)
Casts
Неявные преобразования - Явные преобразования
static_cast - dynamic_cast
const_cast - reinterpret_cast
Выделение памяти
Классы
Свойства функции класса
explicit (C++11)
static
Специальные функции-элементы
Шаблоны
Разное
 
Выражения
Общие
Категории значений (lvalue, rvalue, xvalue)
Порядок оценки (точки последовательности)
Константные выражения
Потенциально оцениваемые выражения
Первичные выражения
Лямбда-выражения(C++11)
Литералы
Целочисленные литералы
Литералы с плавающей запятой
Логические литералы
Символьные литералы, включая управляющие последовательности
Строковые литералы
Литерал нулевого указателя(C++11)
Пользовательский литерал(C++11)
Операторы
a=b, a+=b, a-=b, a*=b, a/=b, a%=b, a&=b, a|=b, a^=b, a<<=b, a>>=b
++a, --a, a++, a--
+a, -a, a+b, a-b, a*b, a/b, a%b, ~a, a&b, a|b, a^b, a<<b, a>>b
a||b, a&&b, !a
a==b, a!=b, a<b, a>b, a<=b, a>=b, a<=>b (начиная с C++20)
a[b], *a, &a, a->b, a.b, a->*b, a.*b
a(...), a,b, a?b:c
выражение new
выражение delete
выражение throw
alignof
sizeof
sizeof...(C++11)
typeid
noexcept(C++11)
Выражения свёртки(C++17)
Альтернативные представления операторов
Приоритет и ассоциативность
Перегрузка операторов
Сравнение по умолчанию(C++20)
Преобразования
Неявные преобразования
Обычные арифметические преобразования
const_cast
static_cast
reinterpret_cast
dynamic_cast
Явные преобразования: (T)a, T(a), auto(a), auto{a} (начиная с C++23)
Пользовательское преобразование
 

Неявные преобразования выполняются всякий раз, когда выражение некоторого типа T1 используется в контексте, который не принимает этот тип, но принимает какой-либо другой T2; в частности:

  • когда выражение используется в качестве аргумента при вызове функции, объявленной с T2 в качестве параметра;
  • когда выражение используется в качестве операнда с оператором, который ожидает T2;
  • при инициализации нового объекта типа T2, включая оператор return в функции, возвращающей T2;
  • когда выражение используется в операторе switch (T2 имеет целочисленный тип);
  • когда выражение используется в операторе if или цикле (T2 равно bool).

Программа корректно сформирована (компилируется) только в том случае, если существует одна однозначная неявная последовательность преобразования из T1 в T2.

Если имеется несколько перегрузок вызываемой функции или оператора, после построения последовательности неявного преобразования из T1 в каждый доступный T2, правила разрешения перегрузки решают, какая перегрузка компилируется.

Примечание: в арифметических выражениях тип назначения для неявных преобразований операндов в бинарных операторах определяется отдельным набором правил: обычные арифметические преобразования

Содержание

[править] Порядок преобразований

Последовательность неявного преобразования состоит из следующего в указанном порядке:

1) ноль или одна стандартная последовательность преобразования;
2) ноль или одно пользовательское преобразование;
3) ноль или одна стандартная последовательность преобразования (только если используется определяемое пользователем преобразование).

При рассмотрении аргумента конструктора или определяемой пользователем функции преобразования допускается только стандартная последовательность преобразования (в противном случае определяемые пользователем преобразования могут быть эффективно объединены в цепочку). При преобразовании из одного неклассового типа в другой неклассовый тип допускается только стандартная последовательность преобразования.

Стандартная последовательность преобразования состоит из следующего, в этом порядке:

1) ноль или одно преобразование из следующего набора: преобразование lvalue-в-rvalue, преобразование массива в указатель и преобразование функции в указатель;
2) ноль или одно числовое продвижение или числовое преобразование;
3) ноль или одно преобразование указателя на функцию;
(начиная с C++17)
4) ноль или одно преобразование квалификации.

Определяемое пользователем преобразование состоит из нуля или одного неявного вызова преобразующего конструктора с одним аргументом или функции преобразования

Говорят, что выражение e неявно преобразуется в T2 тогда и только тогда, когда T2 может быть инициализирован копированием из e, то есть объявление T2 t = e; корректно сформировано (компилируется), для некоторого придуманного временного t. Обратите внимание, что это отличается от прямой инициализации (T2 t(e)), где дополнительно учитываются явные конструкторы и функции преобразования.

[править] Контекстные преобразования

В следующих контекстах ожидается тип bool, и выполняется неявное преобразование, если объявление bool t(e); правильно сформировано (то есть рассматривается функция явного преобразования, такая как explicit T::operator bool() const;). Такое выражение e называется контекстно преобразованным в bool.

  • управляющее выражение if, while, for;
  • операнды встроенных логических операторов !, && и ||;
  • первый операнд условного оператора ?:;
  • предикат в объявлении static_assert;
  • выражение в спецификаторе noexcept;
  • выражение в спецификаторе explicit;
(начиная с C++20)
(начиная с C++11)

В следующих контекстах ожидается контекстно-зависимый тип T, а выражение e типа класса E допускается только в том случае, если E имеет одну неявную определяемую пользователем функцию преобразования в допустимый тип (до C++14)среди допустимых типов есть ровно один тип T, такой что E имеет неявные функции преобразования, возвращаемые типы которых (возможно, cv-квалифицированные) T или ссылка на T (возможно, cv-квалифицированная), а e неявно преобразуется в T (начиная с C++14). Такое выражение e называется контекстно неявно преобразованным к указанному типу T. Обратите внимание, что явные функции преобразования не учитываются, даже если они учитываются при контекстном преобразовании в bool. (начиная с C++11)

  • аргумент выражения delete (T любой тип указателя на объект);
  • целочисленное константное выражение, где используется литеральный класс (T любое целое число или тип перечисления без области видимости (начиная с C++11), выбранная определяемая пользователем функция преобразования должна быть 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) {} // всегда в порядке (неявное преобразование)
}

[править] Преобразования значений

Преобразования значений это преобразования, которые изменяют категорию значений выражения. Они имеют место всякий раз, когда выражение появляется как операнд оператора, который ожидает выражения другой категории значений.

[править] Преобразование lvalue в rvalue

glvalue любого типа, не являющегося функцией или массивом T, может быть неявно преобразовано в prvalue тогоже типа. Если T не относится к классовому типу, это преобразование также удаляет cv-квалификаторы.

Объект, обозначенный glvalue, не доступен, если:

  • преобразование происходит в неоценённом контексте, таком как операнд sizeof, noexcept, decltype, (начиная с C++11) или статической формы typeid
  • glvalue имеет тип std::nullptr_t: в этом случае результирующее значение prvalue является константой нулевого указателя nullptr.
(начиная с C++11)
  • значение, хранящееся в объекте, является константой времени компиляции, и выполняются некоторые другие условия (смотрите Использование ODR)

Если T не относится к классовому типу, значение, содержащееся в объекте, создаётся как результат prvalue. Для типа класса это преобразование

эффективно конструирует копированием временный объект типа T, используя исходное значение glvalue в качестве аргумента конструктора, и этот временный объект возвращается как значение prvalue.

(до C++17)

преобразует glvalue в prvalue, объект результата которого инициализируется копированием с помощью glvalue.

(начиная с C++17)

Это преобразование моделирует акт чтения значения из ячейки памяти в регистр ЦП.

Если объект, на который ссылается glvalue, содержит неопределённое значение (например, полученное инициализацией по умолчанию автоматической переменной, неклассового типа), поведение неопределено за исключением случаев, когда неопределённое значение имеет, возможно, cv-квалифицированный тип unsigned char или std::byte (начиная с C++17).

Поведение также определяется реализацией (а не неопределено), если glvalue содержит значение указателя, которое недействительно.

[править] Преобразование массива в указатель

lvalue или rvalue типа "массив из N T" или "массив неизвестной границы из T" может быть неявно преобразовано в prvalue типа "указатель на T". Если массив является значением prvalue, происходит временная материализация. (начиная с C++17) Результирующий указатель ссылается на первый элемент массива (для подробностей смотрите распад массива в указатель)

Временная материализация

prvalue любого полного типа T может быть преобразовано в xvalue того же типа T. Это преобразование инициализирует временный объект типа T из значения prvalue путём оценки значения prvalue с временным объектом в качестве объекта результата и создаёт значение xvalue, обозначающее временный объект. Если T является классом или массивом типа класса, он должен иметь доступный и не удаляемый деструктор.

struct S { int m; };
int i = S().m; // доступ к элементам ожидает значение glvalue начиная с C++17;
               // S() prvalue преобразуется в xvalue

Временная материализация происходит в следующих ситуациях:

Обратите внимание, что временная материализация не происходит при инициализации объекта из значения prvalue того же типа (путём прямой инициализации или инициализации копированием): такой объект инициализируется непосредственно из инициализатора. Это обеспечивает "гарантированный пропуск копирования".

(начиная с C++17)

[править] Функция в указатель

lvalue типа функции T можно неявно преобразовать в prvalue указатель на эту функцию. Это не относится к нестатическим функциям-элементам, поскольку lvalue, ссылающиеся на нестатические функции-элементы, не существуют.

[править] Числовые продвижения

[править] Целочисленное продвижение

prvalue небольших целочисленных типов (например, char) могут быть преобразованы в prvalue более крупных целочисленных типов (например, int). В частности, арифметические операторы не принимают в качестве аргументов типы меньше int, а целочисленные продвижения автоматически применяются после преобразования lvalue в rvalue, если это применимо. Это преобразование всегда сохраняет значение.

Следующие неявные преобразования классифицируются как целочисленные продвижения:

  • signed char или signed short можно преобразовать в int;
  • unsigned char или unsigned short можно преобразовать в int, если он может содержать весь диапазон значений, и unsigned int в противном случае;
  • char можно преобразовать в int или unsigned int в зависимости от базового типа: signed char или unsigned char (смотрите выше);
  • wchar_t, char8_t (начиная с C++20), char16_t и char32_t (начиная с C++11) могут быть преобразованы в первый тип из следующего списка, способного содержать весь их диапазон значений: int, unsigned int, long, unsigned long, long long, unsigned long long (начиная с C++11);
  • тип перечисления с незаданной областью видимости (начиная с C++11), базовый тип которого не является фиксированным, может быть преобразован в первый тип из следующего списка, который может содержать весь диапазон значений: int, unsigned int, long, unsigned long, long long или unsigned long long, расширенные целые типы с более высоким рангом преобразования (в порядке ранжирования, знаковый имеет предпочтение перед беззнаковым) (начиная с C++11). Если диапазон значений больше, целочисленные преобразования не применяются;
  • тип перечисления с незаданной областью видимости (начиная с C++11), базовый тип которого является фиксированным, может быть преобразован в его базовый тип и, если базовый тип также подлежит целочисленному продвижению, в продвинутый базовый тип. Преобразование в не продвигаемый базовый тип лучше для разрешения перегрузки;
  • тип битового поля может быть преобразован в int, если он может представлять весь диапазон значений битового поля, иначе в unsigned int, если он может представлять весь диапазон значений битового поля, в противном случае целочисленные продвижения не применяются;
  • тип bool можно преобразовать в int, при этом значение false становится 0 а true становится 1.

Обратите внимание, что все остальные преобразования не являются продвижениями; например, разрешение перегрузки выбирает char -> int (продвижение) вместо char -> short (преобразование).

[править] Продвижение с плавающей запятой

prvalue типа float можно преобразовать в prvalue типа double. Значение не меняется.

[править] Числовые преобразования

В отличие от продвижений, числовые преобразования могут изменить значения с потенциальной потерей точности.

[править] Целочисленные преобразования

prvalue целочисленного типа или типа перечисления без области видимости (начиная с C++11) может быть преобразовано в любой другой целочисленный тип. Если преобразование указано в разделе целочисленных продвижений, это продвижение, а не преобразование.

  • Если целевой тип беззнаковый, результирующее значение является наименьшим беззнаковым значением, равным исходному значению по модулю 2n
    , где n количество битов, используемых для представления типа назначения.
То есть, в зависимости от того, является ли тип назначения более широким или более узким, целые числа со знаком расширяются по знаку[сноска 1] или усечением, а целые числа без знака дополняются нулём или усекаются соответственно.
  • Если целевой тип знаковый, значение не изменяется, если исходное целое число может быть представлено в целевом типе. В противном случае результат определяется реализацией (до C++20)это уникальное значение целевого типа, равное исходному значению по модулю 2n
    , где n это количество битов, используемых для представления целевого типа.
    (начиная с C++20)
    . (Обратите внимание, что это отличается от целочисленного арифметического переполнения со знаком, которое не определено).
  • Если исходным типом является bool, значение false преобразуется в ноль, а значение true преобразуется в значение один целевого типа (обратите внимание, что если тип назначения int, это целочисленное продвижение, а не целочисленное преобразование).
  • Если целевой тип bool, это логическое преобразование (смотрите ниже).

[править] Преобразования с плавающей запятой

prvalue типа с плавающей запятой можно преобразовать в prvalue любого другого типа с плавающей запятой. Если преобразование указано в продвижениях с плавающей запятой, это продвижение, а не преобразование.

  • Если исходное значение может быть точно представлено в целевом типе, оно не изменяется.
  • Если исходное значение находится между двумя представляемыми значениями целевого типа, результатом является одно из этих двух значений (определяется реализацией, какое из двух, но, если поддерживается арифметика IEEE, округление по умолчанию до ближайшего).
  • В противном случае поведение не определено.

[править] Преобразования плавающей запятой в целое

  • prvalue типа с плавающей запятой можно преобразовать в prvalue любого целочисленного типа. Дробная часть усекается, то есть отбрасывается. Если значение не может уместиться в целевом типе, поведение не определено (даже если целевой тип беззнаковый, арифметика по модулю не применяется). Если целевой тип bool, это логическое преобразование (смотрите ниже).
  • Значение prvalue целого числа или типа перечисления с незаданной областью видимости (начиная с C++11) можно преобразовать в значение prvalue любого типа с плавающей запятой. Результат точен, насколько это возможно. Если значение может уместиться в целевом типе, но не может быть представлено точно, реализация определяет, будет ли выбрано ближайшее более высокое или ближайшее более низкое представляемое значение, но, если поддерживается арифметика IEEE, округление по умолчанию до ближайшего. Если значение не умещается в целевом типе, поведение не определено. Если исходный тип bool, значение false преобразуется в ноль, а значение true преобразуется в единицу.

[править] Преобразования указателя

  • Константа нулевого указателя (смотрите NULL), может быть преобразована в любой тип указателя, и результатом будет значение нулевого указателя этого типа. Такое преобразование (известное как преобразование нулевого указателя) разрешено для преобразования в cv-квалифицированный тип как одно преобразование, то есть оно не считается комбинацией числовых и квалификационных преобразований.
  • Указатель prvalue на любой (необязательно cv-квалифицированный) объектный тип T может быть преобразован в указатель prvalue на (cv-квалифицированный) void. Результирующий указатель представляет то же место в памяти, что и исходное значение указателя. Если исходный указатель является нулевым значением указателя, результатом является значение нулевого указателя целевого типа.
  • Указатель prvalue на тип производного класса (необязательно cv-квалифицированного) может быть преобразован в указатель prvalue на его базовый класс (cv-квалифицированный). Если базовый класс недоступен или неоднозначен, преобразование имеет неправильный формат (не будет компилироваться). Результатом преобразования является указатель на подобъект базового класса в указанном объекте. Значение нулевого указателя преобразуется в значение нулевого указателя целевого типа.

[править] Преобразования указателя на элемент

  • Константа нулевого указателя (смотрите NULL) может быть преобразована в любой тип указателя на элемент, и результатом будет значение нулевого указателя на элемент этого типа. Такое преобразование (известное как преобразование пустого указателя на элемент) может преобразовывать в cv-квалифицированный тип как одно преобразование, то есть оно не считается комбинацией числовых и квалификационных преобразований.
  • Указатель prvalue на элемент некоторого типа T в базовом классе B может быть преобразован в prvalue указатель на элемент того же типа T в его производном классе D. Если B недоступен, неоднозначен или является виртуальным базовым для D или является базовым для некоторого промежуточного виртуального базового для D, преобразование некорректно (не компилируется). Результирующий указатель может быть разыменован с помощью объекта D, и он будет обращаться к элементу внутри базового подобъекта B этого объекта D. Значение нулевого указателя преобразуется в значение нулевого указателя целевого типа.

[править] Логические преобразования

prvalue типы целого, с плавающей запятой, перечисления без области видисмоти (начиная с C++11), указателя и указателя на элемент могут быть преобразованы в prvalue типа bool.

Нулевое значение (для целого, с плавающей запятой и перечисления без области видимости (начиная с C++11)) и нулевой указатель и значения нулевого указателя на элемент становятся false. Все остальные значения становятся true.

В контексте прямой инициализации объект bool может быть инициализирован значением prvalue типа std::nullptr_t, включая nullptr. Результирующее значение равно false. Однако это не считается неявным преобразованием.

(начиная с C++11)

[править] Квалификационные преобразования

  • Указатель типа prvalue на cv-квалифицированный тип T может быть преобразован в указатель prvalue на более точную cv-квалификацию того же типа T (другими словами, можно добавить const и volatile).
  • Значение prvalue типа указателя на элемент cv-квалифицированного типа T в классе X может быть преобразовано в prvalue-указатель на элемент более точно cv-квалифицированного типа T в классе X.

"Более точно" cv-квалифицированного означает, что

  • указатель на неквалифицированный тип может быть преобразован в указатель на const;
  • указатель на неквалифицированный тип может быть преобразован в указатель на volatile;
  • указатель на неквалифицированный тип может быть преобразован в указатель на const volatile;
  • указатель на тип const может быть преобразован в указатель на const volatile;
  • указатель на тип volatile может быть преобразован в указатель на const volatile.

Для многоуровневых указателей применяются следующие ограничения: многоуровневый указатель P1, который является cv1
0
-квалифицированным указателем на cv1
1
-квалифицированный указатель на ... cv1
n-1
-квалифицированный указатель на cv1
n
-квалифицированный T можно преобразовать в многоуровневый указатель P2, который является cv2
0
-квалифицированным указателем на cv2
1
-квалифицированный указатель на ... cv2
n-1
-квалифицированный указатель на cv2
n
-квалифицированный T только если

  • количество уровней n одинаково для обоих указателей;
  • на каждом уровне, в котором участвует тип массива, по крайней мере один тип массива имеет неизвестную границу, или оба типа массива имеют одинаковый размер;
(начиная с C++20)
  • если есть const в квалификации cv1
    k
    на каком-то уровне (кроме нулевого) P1, есть const на том же уровне cv2
    k
    P2;
  • если есть volatile в квалификации cv1
    k
    на каком-то уровне (кроме нулевого) P1, есть volatile на том же уровне cv2
    k
    P2;
  • если на каком-то уровне (отличном от нулевого) уровня P1, существует тип массива с неизвестной границей, то на том же уровне P2 есть тип массива с неизвестной границей;
(начиная с C++20)
  • если на каком-то уровне k P2 является более точно cv-квалифицированным, чем P1 или есть тип массива с известной границей в P1 и тип массива с неизвестной границей в P2 (начиная с C++20), тогда должен быть const на каждом отдельном уровень (кроме нулевого уровня) P2 до k: cv2
    1
    , cv2
    2
    ... cv2
    k
    .
  • одни и те же правила применяются к многоуровневым указателям на элементы и многоуровневым смешанным указателям на объекты и указатели на элементы;
  • те же правила применяются к многоуровневым указателям, которые включают указатели на массив известных или неизвестных границ на любом уровне (массивы cv-квалифицированных элементов сами считаются идентично cv-квалифицированными);
  • к нулевому уровню применяются правила преобразования немногоуровневых квалификаций.
char** p = 0;
const char** p1 = p; // ошибка: уровень 2 более точно cv-квалифицирован,
                     // но уровень 1 не является const
const char* const * p2 = p; // OK: уровень 2 более точно cv-квалифицирован
                            // и const добавлено на уровень 1
volatile char * const * p3 = p; // OK: уровень 2 более точно cv-квалифицирован и const
                                // добавлено на уровень 1
volatile const char* const* p4 = p2; // OK: уровень 2 более точно cv-квалифицирован и
                                     // const уже существует на уровне 1
 
double *a[2][3];
double const * const (*ap)[3] = a; // OK
double * const (*ap1)[] = a;       // OK, начиная с C++20

Обратите внимание, что в языке программирования C, const/volatile можно добавить только к первому уровню:

char** p = 0;
char * const* p1 = p;       // OK в C и C++
const char* const * p2 = p; // ошибка в C, OK в C++

Преобразования указателя на функцию

  • Указатель типа prvalue на негенерирующую исключения функцию может быть преобразован в указатель prvalue на потенциально генерирующую исключения функцию.
  • Указатель типа prvalue на негенерирующую исключения функцию-элемент может быть преобразован в указатель prvalue на потенциально генерирующую исключения функцию-элемент.
void (*p)();
void (**pp)() noexcept = &p; // ошибка: невозможно преобразовать в указатель
                             // на функцию noexcept
 
struct S
{
    typedef void (*p)();
    operator p();
};
void (*q)() noexcept = S(); // ошибка: невозможно преобразовать в указатель
                            // на функцию noexcept
(начиная с C++17)

[править] Проблема безопасного bool

До введения явных функций преобразования в C++11 разработка класса, который можно было бы использовать в логических контекстах (например, if(obj) { ... }) представляла собой проблему: при наличии определяемой пользователем функции преобразования, такой как T::operator bool() const;, неявная последовательность преобразования допускала одну дополнительную стандартную последовательность преобразования после вызова этой функции, что означает, что результирующий bool мог быть преобразован в int, допуская такой код, как obj << 1; or int i = obj;.

Одно раннее решение для этого можно увидеть в std::basic_ios, который определяет operator! и operator void*(до C++11), чтобы такой код, как if(std::cin) {...} компилировался, поскольку void* преобразуется в bool, но int n = std::cout; не компилируется, потому что void* нельзя преобразовать в int. Это по-прежнему позволяет компилировать бессмысленный код, такой как delete std::cout;, и многие сторонние библиотеки до C++11 были разработаны с использованием более сложного решения, известного как Идиома Безопасного Bool (Safe Bool).

Явное преобразование bool также можно использовать для решения проблемы безопасного bool

explicit operator bool() const { ... }
(начиная с C++11)

[править] Сноски

  1. Это применимо только в том случае, если арифметика представляет собой дополнение до двух, которое требуется только для целочисленных типов точной ширины. Обратите внимание, однако, что на данный момент все платформы с компилятором C++ используют арифметику с дополнением до двух

[править] Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

Номер Применён Поведение в стандарте Корректное поведение
CWG 172 C++98 тип перечисления продвигается на основе его базового типа вместо этого на основе его диапазона значений
CWG 330 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 1781 C++11 std::nullptr_t в bool считается неявным преобразованием,
даже если оно допустимо только для прямой инициализации
больше не считается неявным преобразованием
CWG 1787 C++98 поведение чтения из неопределённого unsigned char,
кэшированного в регистре, было неопределённым
сделано чётко определённым
CWG 2484 C++20 char8_t и char16_t имеют разные целочисленные
стратегии продвижения, но они подходят обоим
char8_t следует продвигать так же, как
char16_t

[править] Смотрите также

Документация C по Неявные преобразования