Явное преобразование типов
Преобразует типы с использованием комбинации явного и неявного преобразований.
Синтаксис
( целевой тип ) выражение | (1) | |
целевой тип ( список выражений (необязательно) ) | (2) | |
целевой тип { список выражений (необязательно) } | (3) | (с C++11) |
имя шаблона ( список выражений (необязательно) ) | (4) | (с C++17) |
имя шаблона { список выражений (необязательно) } | (5) | (с C++17) |
auto ( выражение ) | (6) | (с C++23) |
auto { выражение } | (7) | (с C++23) |
Возвращает значение типа целевой тип.
Объяснение
const_cast<target-type>(expression);static_cast<target-type>(expression), с расширениями: указатель или ссылка на производный класс дополнительно разрешено привести к указателю или ссылке на недвусмысленный базовый класс (и наоборот), даже если базовый класс недоступен (то есть, это приведение игнорирует спецификатор закрытого наследования). То же самое относится к приведению указателя на член к указателю на член недвусмысленного невиртуального базового класса;static_cast (с расширениями) за которым следует const_cast;reinterpret_cast<target-type>(expression);reinterpret_cast за которым следует const_cast.
static_cast за которым следует const_cast, оно не может быть скомпилировано.static_cast или reinterpret_cast будет выбрано.unsigned int(expression) и int*(expression) не являются допустимыми), за которым следует список выражений, разделенных запятыми, в скобках. - Если в скобках находится ровно одно выражение, это выражение приведения точно эквивалентно соответствующему выражению приведения в стиле C.
- Если в скобках находится более одного выражения или список инициализации(с C++11) , целевой тип должен быть классом с соответствующим объявленным конструктором. Это выражение представляет собой prvalue типа целевой тип обозначающее временное значение(до C++17)объект результата которого (с C++17) прямо инициализируется списком список выражений.
- Если в скобках нет выражения: если целевой тип называет не массивный полный тип объекта, это выражение представляет собой prvalue типа целевой тип, обозначающее временное значение(до C++17)объект результата которого (возможно, с добавленными cv-квалификаторами)(с C++17) этого типа. Если целевой тип является типом объекта, объект инициализируется по умолчанию. Если целевой тип (возможно cv-квалифицированный) void, выражение представляет собой prvalue типа void без объекта результата(с C++17).
void, выражение представляет собой void prvalue без объекта результата(с C++17). Это единственное выражение приведения, которое может создать массив prvalue.(до C++20)
auto заменяется на выведенный тип вымышленной переменной x объявленной с auto x(expression); (которая никогда не интерпретируется как объявление функции) или auto x{expression};, соответственно. Результат всегда представляет собой prvalue объекта типа.Как и во всех выражениях приведения, результат:
- является lvalue, если целевой тип является типом lvalue ссылки или rvalue ссылкой на тип функции(с C++11);
| (с C++11) |
- является prvalue в противном случае.
Разрешение неоднозначностей
Неоднозначное объявление оператора
В случае неоднозначности между выражением оператора с функциональным приведением как его левым подвыражением и оператором объявления, неоднозначность разрешается, рассматривая его как оператор объявления. Это разрешение неоднозначности чисто синтаксическое: оно не учитывает значение имен, встречающихся в операторе, кроме того, являются ли они именами типов:
struct M {};
struct L { L(M&); };
M n;
void f()
{
M(m); // declaration, equivalent to M m;
L(n); // ill-formed declaration, equivalent to L n;
L(l)(m); // still a declaration, equivalent to L l((m));
}| Однако, если внешний декларатор в неоднозначном операторе объявления имеет тип возврата с хвостом, оператор будет рассматриваться только как оператор объявления, если тип возврата с хвостом начинается с 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)); // function declaration: has a parameter `a` of type int
S x(int()); // function declaration: has an unnamed parameter of type int(*)()
// that is adjusted from int()
// Ways to avoid ambiguity:
S y((int(a))); // object declaration: extra pair of parentheses
S y((int)a); // object declaration: C-style cast
S z = int(a); // object declaration: no ambiguity for this syntax
}| Однако, если внешний декларатор в неоднозначном параметре объявления имеет тип возврата с хвостом, неоднозначность будет разрешена только как объявление, если она начинается с auto: typedef struct BB { int C[2]; } *B, C;
void foo()
{
S a(B()->C); // object declaration: B()->C cannot declare a parameter
S b(auto()->C); // function declaration: has an unnamed parameter of type C(*)()
// that us adjusted from C()
} | (с C++11) |
Неоднозначный type-id
Неоднозначность может возникнуть из-за сходства между функциональным приведением и type-id. Решение состоит в том, что любая конструкция, которая потенциально может быть type-id в её синтаксическом контексте, должна рассматриваться как type-id:
// `int()` and `int(unsigned(a))` can both be parsed as type-id:
// `int()` represents a function returning int
// and taking no argument
// `int(unsigned(a))` represents a function returning int
// and taking an argument of type unsigned
void foo(signed char a)
{
sizeof(int()); // type-id (ill-formed)
sizeof(int(a)); // expression
sizeof(int(unsigned(a))); // type-id (ill-formed)
(int()) + 1; // type-id (ill-formed)
(int(a)) + 1; // expression
(int(unsigned(a))) + 1; // type-id (ill-formed)
}| Однако, если внешний абстрактный дескриптор в неоднозначном идентификаторе типа имеет возвращаемый тип в конце, неоднозначность будет разрешена только путём его обработки как идентификатор типа, если он начинается с 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++.
| Отчёт об ошибке | Применено к | Поведение, как опубликовано | Правильное поведение |
|---|---|---|---|
|
CWG 1223 (P2915R0) | C++11 | добавление возвращаемого типа в конце привело к новым неоднозначностям | разрешает их |
| CWG 2620 | C++98 | разрешение неоднозначных параметров функции может быть неправильно истолковано | улучшена формулировка |
Ссылки
- Стандарт C++23 (ISO/IEC 14882:2023):
- 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 | добавляет или удаляет const |
Преобразование static_cast | выполняет основные преобразования |
Преобразование dynamic_cast | выполняет проверенные полиморфные преобразования |
Преобразование reinterpret_cast | выполняет общие преобразования низкого уровня |
| Стандартные преобразования | неявные преобразования из одного типа в другой |
| Документация C для оператора каста | |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/explicit_cast