Explicit type conversion
Преобразует между типами, используя комбинацию явных и неявных преобразований.
Содержание |
Синтаксис
(
type-id
)
unary-expression
|
(1) | ||||||||
simple-type-specifier
(
expression-list
(необязательно)
)
simple-type-specifier
(
initializer-list
(необязательно)
)
|
(2) |
(до C++11)
(начиная с C++11) |
|||||||
simple-type-specifier
{
initializer-list
(необязательно)
}
|
(3) | (начиная с C++11) | |||||||
simple-type-specifier
{
designated-initializer-list
}
|
(4) | (начиная с C++20) | |||||||
typename
identifier
(
initializer-list
(необязательно)
)
|
(5) | (начиная с C++11) | |||||||
typename
identifier
{
initializer-list
(необязательно)
}
|
(6) | (начиная с C++11) | |||||||
typename
identifier
{
designated-initializer-list
}
|
(7) | (начиная с C++20) | |||||||
Явно преобразует любое количество значений в значение целевого типа.
| type-id | - | a type-id |
| unary-expression | - | унарное выражение (чей оператор верхнего уровня не имеет приоритета выше, чем у C-style приведения) |
| simple-type-specifier | - | a simple type specifier |
| expression-list | - | список выражений, разделённых запятыми (за исключением не заключённых в скобки comma expressions ) |
| initializer-list | - | список, разделённый запятыми, initializer clauses |
| designated-initializer-list | - | список, разделённый запятыми, designated initializer clauses |
| identifier | - | (возможно, квалифицированный) идентификатор (включая template identifiers ) |
Объяснение
const_cast
<
type-id
>
(
unary-expression
)
;
static_cast
<
type-id
>
(
unary-expression
)
, с расширениями: указатель или ссылка на
производный класс
дополнительно может быть приведён к указателю или ссылке на однозначный базовый класс (и наоборот), даже если базовый класс
недоступен
(то есть это приведение игнорирует спецификатор закрытого наследования). То же самое применяется к приведению
указателя на член
к указателю на член однозначного невиртуального базового класса;
reinterpret_cast
<
type-id
>
(
unary-expression
)
;
T
, который определяется из указанного типа
и инициализатора
(since C++17)
:
|
|
(until C++17) | ||
|
|
(since C++17) |
- Если функциональное приведение имеет синтаксис (2) и в скобках находится ровно одно выражение, это приведение эквивалентно соответствующему C-стилю приведения.
-
В противном случае, если
Tявляется (возможно, cv-квалифицированным) void , результат представляет собой rvalue (до C++11) prvalue (начиная с C++11) типа void , который не выполняет инициализацию.
|
(до C++11) |
|
(начиная с C++11) |
-
В противном случае, если
Tявляется ссылочным типом, функциональное приведение имеет тот же эффект, что и прямая инициализация созданной переменной t типаTиз указанного инициализатора, и результатом является инициализированная t .
|
(до C++11) |
|
(начиная с C++11) |
-
В противном случае результат представляет собой
rvalue
(до C++11)
prvalue
(начиная с C++11)
типа
Tобозначающий временный объект (до C++17) чей результирующий объект (начиная с C++17) прямо инициализируется указанным инициализатором.
Разрешение неоднозначностей
Неоднозначное объявление
В случае неоднозначности между оператором выражения с функциональной записью приведения типа в качестве крайнего левого подвыражения и оператором объявления, неоднозначность разрешается путём трактовки его как объявления. Это устранение неоднозначности является чисто синтаксическим: оно не учитывает смысл имён, встречающихся в операторе, за исключением того, являются ли они именами типов:
struct M {}; struct L { L(M&); }; M n; void f() { M(m); // объявление, эквивалентно M m; L(n); // некорректное объявление, эквивалентно L n; L(l)(m); // всё ещё объявление, эквивалентно L l((m)); }
|
Однако, если самый внешний декларатор в неоднозначном объявлении имеет trailing return type , оператор будет рассматриваться как объявление только если trailing return type начинается с auto : struct M; struct S { S* operator()(); int N; int M; void mem(S s) { auto(s)()->M; // expression (S::M hides ::M), invalid before C++23 } }; void f(S s) { { auto(s)()->N; // expression, invalid before C++23 auto(s)()->M; // function declaration, equivalent to M s(); } { S(s)()->N; // expression S(s)()->M; // expression } } |
(начиная с C++11) |
Неоднозначный параметр функции
Упомянутая выше неоднозначность также может возникать в контексте объявления. В этом контексте выбор стоит между объявлением объекта с функциональным приведением в качестве инициализатора и объявлением, включающим функциональный декларатор с избыточным набором скобок вокруг имени параметра. Разрешение также заключается в том, чтобы рассматривать любую конструкцию, такую как потенциальное объявление параметра, которая может быть объявлением, как объявление:
struct S { S(int); }; void foo(double a) { S w(int(a)); // объявление функции: имеет параметр `a` типа int S x(int()); // объявление функции: имеет безымянный параметр типа int(*)() // который преобразуется из int() // Способы избежать неоднозначности: S y((int(a))); // объявление объекта: дополнительные скобки S y((int)a); // объявление объекта: C-style приведение типа S z = int(a); // объявление объекта: нет неоднозначности для этого синтаксиса }
|
Однако, если самый внешний декларатор в неоднозначном объявлении параметра имеет trailing return type , неоднозначность будет разрешена только путём трактовки его как объявления, если оно начинается с auto : typedef struct BB { int C[2]; } *B, C; void foo() { S a(B()->C); // объявление объекта: B()->C не может объявлять параметр S b(auto()->C); // объявление функции: имеет безымянный параметр типа C(*)() // который преобразован из C() } |
(начиная с C++11) |
Неоднозначный type-id
Неоднозначность может возникнуть из-за схожести между функциональной формой приведения и type-id . Разрешение заключается в том, что любая конструкция, которая может быть type-id в своем синтаксическом контексте, должна рассматриваться как type-id:
// `int()` и `int(unsigned(a))` могут быть разобраны как type-id: // `int()` представляет функцию, возвращающую int // и не принимающую аргументов // `int(unsigned(a))` представляет функцию, возвращающую int // и принимающую аргумент типа unsigned void foo(signed char a) { sizeof(int()); // type-id (некорректно) sizeof(int(a)); // выражение sizeof(int(unsigned(a))); // type-id (некорректно) (int()) + 1; // type-id (некорректно) (int(a)) + 1; // выражение (int(unsigned(a))) + 1; // type-id (некорректно) }
|
Однако, если самый внешний abstract-declarator в неоднозначном type-id имеет trailing return type , неоднозначность будет разрешена только путем трактовки его как type-id, если он начинается с auto : typedef struct BB { int C[2]; } *B, C; void foo() { sizeof(B()->C[1]); // OK, sizeof(expression) sizeof(auto()->C[1]); // error: sizeof of a function returning an array } |
(начиная с C++11) |
Примечания
| Макрос тестирования возможностей | Значение | Стандарт | Возможность |
|---|---|---|---|
__cpp_auto_cast
|
202110L
|
(C++23) | auto ( x ) и auto { x } |
Пример
#include <cassert> #include <iostream> double f = 3.14; unsigned int n1 = (unsigned int)f; // C-style cast unsigned int n2 = unsigned(f); // function-style cast class C1; class C2; C2* foo(C1* p) { return (C2*)p; // casts incomplete type to incomplete type } void cpp23_decay_copy_demo() { auto inc_print = [](int& x, const int& y) { ++x; std::cout << "x:" << x << ", y:" << y << '\n'; }; int p{1}; inc_print(p, p); // prints x:2 y:2, because param y here is an alias of p int q{1}; inc_print(q, auto{q}); // prints x:2 y:1, auto{q} (C++23) casts to prvalue, // so the param y is a copy of q (not an alias of q) } // In this example, C-style cast is interpreted as static_cast // even though it would work as reinterpret_cast struct A {}; struct I1 : A {}; struct I2 : A {}; struct D : I1, I2 {}; int main() { D* d = nullptr; // A* a = (A*)d; // compile-time error A* a = reinterpret_cast<A*>(d); // this compiles assert(a == nullptr); cpp23_decay_copy_demo(); }
Вывод:
x:2 y:2 x:2 y:1
Отчёты о дефектах
Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C++.
| DR | Применяется к | Поведение в опубликованной версии | Корректное поведение |
|---|---|---|---|
|
CWG 1223
( P2915R0 ) |
C++11 | добавление завершающего возвращаемого типа ввело больше неоднозначностей | разрешает их |
| CWG 1893 | C++11 | функциональное приведение не учитывало развертывания пакетов | учитывает их |
| CWG 2351 | C++11 | void { } было некорректным | сделано корректным |
| CWG 2620 | C++98 |
разрешение неоднозначных параметров функции
могло быть неверно истолковано |
улучшена формулировка |
| CWG 2828 | C++98 |
C-стиль приведения был некорректным, если существуют множественные интерпретации
static_cast с последующим const_cast , независимо от того, используются ли эти преобразования фактически |
учитывает только
преобразования, которые могут быть использованы |
| CWG 2894 | C++98 | функциональные приведения могли создавать rvalue-ссылки | могут создавать только lvalue-ссылки |
Ссылки
- Стандарт C++23 (ISO/IEC 14882:2024):
-
- 7.6.1.4 Явное преобразование типа (функциональная нотация) [expr.type.conv]
-
- 7.6.3 Явное преобразование типа (нотация приведения) [expr.cast]
- Стандарт C++20 (ISO/IEC 14882:2020):
-
- 7.6.1.4 Явное преобразование типа (функциональная нотация) [expr.type.conv]
-
- 7.6.3 Явное преобразование типа (нотация приведения) [expr.cast]
- Стандарт C++17 (ISO/IEC 14882:2017):
-
- 8.2.3 Явное преобразование типа (функциональная нотация) [expr.type.conv]
-
- 8.4 Явное преобразование типа (нотация приведения) [expr.cast]
- Стандарт C++14 (ISO/IEC 14882:2014):
-
- 5.2.3 Явное преобразование типа (функциональная нотация) [expr.type.conv]
-
- 5.4 Явное преобразование типа (нотация приведения) [expr.cast]
- Стандарт C++11 (ISO/IEC 14882:2011):
-
- 5.2.3 Явное преобразование типа (функциональная нотация) [expr.type.conv]
-
- 5.4 Явное преобразование типа (нотация приведения) [expr.cast]
- Стандарт C++03 (ISO/IEC 14882:2003):
-
- 5.2.3 Явное преобразование типа (функциональная нотация) [expr.type.conv]
-
- 5.4 Явное преобразование типа (нотация приведения) [expr.cast]
- Стандарт C++98 (ISO/IEC 14882:1998):
-
- 5.2.3 Явное преобразование типа (функциональная нотация) [expr.type.conv]
-
- 5.4 Явное преобразование типа (нотация приведения) [expr.cast]
Смотрите также
const_cast
conversion
|
добавляет или удаляет const |
static_cast
conversion
|
выполняет базовые преобразования |
dynamic_cast
conversion
|
выполняет проверенные полиморфные преобразования |
reinterpret_cast
conversion
|
выполняет общие низкоуровневые преобразования |
| стандартные преобразования | неявные преобразования из одного типа в другой |
|
документация по C
для
оператора приведения
|
|