static_cast
conversion
Преобразует между типами, используя комбинацию неявных и пользовательских преобразований.
Содержание |
Синтаксис
static_cast<
целевой-тип
>(
выражение
)
|
|||||||||
Возвращает значение типа target-type .
Объяснение
Только следующие преобразования могут быть выполнены с помощью static_cast , за исключением случаев, когда такие преобразования снимают константность (или волатильность).
Base
" и
target-type
является "ссылкой на
cv2
Derived
", результат ссылается на объект типа
Derived
, содержащий
expression
, если выполняются все следующие условия:
-
Derivedявляется полным типом класса. -
Baseявляется базовым классомDerived. - cv1 не является более строгой cv-квалификацией, чем cv2 .
-
Baseявляется виртуальным базовым классом дляDerived. -
Baseявляется базовым классом виртуального базового класса дляDerived. -
Не существует допустимого
стандартного преобразования
из «указателя на
Derived» в «указатель наBase».
Derived
, поведение не определено.
struct B {}; struct D : B { B b; }; D d; B& br1 = d; B& br2 = d.b; static_cast<D&>(br1); // OK, lvalue обозначает исходный объект "d" static_cast<D&>(br2); // UB: подобъект "b" не является подобъектом базового класса
|
2)
Если
target-type
является «rvalue-ссылка на
Derived
» и
expression
является xvalue типа «(возможно cv-квалифицированный)
Base
» так, что
Base
является базовым классом
Derived
, результат и ограничения такого преобразования совпадают с преобразованием «lvalue
Base
в ссылку на
Derived
».
3)
Если
target-type
является типом rvalue-ссылки и ссылочный тип
совместим по ссылке
с типом
expression
,
static_cast
преобразует значение
glvalue, class prvalue или array prvalue
(до C++17)
любого lvalue
(начиная с C++17)
expression
в xvalue, ссылающийся на тот же объект, что и выражение, или на его базовый подобъект (в зависимости от
target-type
).
[1]
Если
target-type
является недоступным или неоднозначным базовым классом типа
expression
, программа является некорректной.
|
(начиная с C++11) |
|
объявление target-type temp ( expression ) ; корректно для некоторой вымышленной временной переменной temp . Эффект такого явного преобразования эквивалентен выполнению объявления и инициализации с последующим использованием temp в качестве результата преобразования. expression используется как lvalue (до C++11) glvalue (начиная с C++11) тогда и только тогда, когда инициализация использует его как lvalue (до C++11) glvalue (начиная с C++11) . |
(до C++17) | ||
|
удовлетворяется любое из следующих условий:
Явное преобразование определяется следующим образом:
|
(начиная с C++17) |
- lvalue-to-rvalue conversion
- array-to-pointer conversion
- function-to-pointer conversion
- null pointer conversion
- null member pointer conversion
- boolean conversion
| (since C++17) |
|
a)
Значение типа
scoped enumeration
может быть преобразовано в целочисленный или тип с плавающей точкой.
|
(начиная с C++11) |
- Если target-type имеет фиксированный базовый тип, expression сначала преобразуется в этот тип с помощью integral promotion или integral conversion , если необходимо, а затем в target-type .
- Если target-type не имеет фиксированного базового типа, значение expression остаётся неизменным, если исходное значение находится в диапазоне значений перечисления , в противном случае поведение не определено.
|
d)
Правостое значение типа с плавающей запятой может быть явно преобразовано в любой другой тип с плавающей запятой.
|
(since C++23) |
Base
» может быть явно преобразовано в тип «указатель на
cv2
Derived
», если выполняются все следующие условия:
-
Derivedявляется полным типом класса. -
Baseявляется базовым классом дляDerived. - cv1 не является более строгой cv-квалификацией, чем cv2 .
Derived
, содержащий объект типа
Base
, на который указывает
expression
.
-
Baseявляется виртуальным базовым классом дляDerived. -
Baseявляется базовым классом виртуального базового класса дляDerived. -
Не существует допустимого стандартного преобразования из «указатель на
Derived» в «указатель наBase».
Derived
, поведение не определено.
Derived
типа
cv1
T
» может быть явно преобразовано в тип «указатель на член
Base
типа
cv2
T
» при выполнении всех следующих условий:
-
Derivedявляется полным типом класса. -
Baseявляется базовым классомDerived. - cv1 не является более строгой cv-квалификацией, чем cv2 .
Base
.
Base
типа
T
" в "указатель на член
Derived
типа
T
", программа является некорректной.
Base
, поведение не определено.
T
", если
T
является объектным типом и
cv1
не является более строгой cv-квалификацией, чем
cv2
.
|
(до C++17) |
|
(начиная с C++17) |
Как и для всех выражений приведения, результат:
- lvalue, если target-type является типом lvalue-ссылки или rvalue-ссылкой на тип функции (начиная с C++11) ;
|
(since C++11) |
- в противном случае является prvalue.
- ↑ Этот тип static_cast используется для реализации семантики перемещения в std::move .
- ↑ Если поддерживается арифметика IEEE, округление по умолчанию происходит к ближайшему значению.
Указательно-конвертируемые объекты
Два объекта a и b являются pointer-interconvertible если:
- они являются одним и тем же объектом, или
- один является объектом объединения, а другой - нестатическим элементом данных этого объекта, или
- один является стандартно-компонуемым объектом класса, а другой - первым нестатическим элементом данных этого объекта или любого подобъекта базового класса этого объекта, или
- существует объект c такой, что a и c являются pointer-interconvertible, и c и b являются pointer-interconvertible.
union U { int a; double b; } u; void* x = &u; // значение x — «указатель на u» double* y = static_cast<double*>(x); // значение y — «указатель на u.b» char* z = static_cast<char*>(x); // значение z — «указатель на u»
Примечания
Преобразования из базового класса в производный (
понижающие приведения
) с использованием
static_cast
не выполняют проверок во время выполнения, чтобы убедиться, что
динамический тип
указываемого/ссылаемого объекта является
Derived
, и могут безопасно использоваться только если это предусловие гарантировано другими средствами, например при реализации
статического полиморфизма
. Безопасное понижающее приведение может быть выполнено с помощью
dynamic_cast
.
static_cast также может использоваться для разрешения неоднозначности перегруженных функций путем выполнения преобразования функции в указатель определенного типа, как в
std::for_each(files.begin(), files.end(), static_cast<std::ostream&(*)(std::ostream&)>(std::flush));
Ключевые слова
Пример
#include <iostream> #include <vector> struct B { int m = 42; const char* hello() const { return "Hello world, this is B!\n"; } }; struct D : B { const char* hello() const { return "Hello world, this is D!\n"; } }; enum class E { ONE = 1, TWO, THREE }; enum EU { ONE = 1, TWO, THREE }; int main() { // 1. статическое приведение вниз D d; B& br = d; // приведение вверх через неявное преобразование std::cout << "1) " << br.hello(); D& another_d = static_cast<D&>(br); // приведение вниз std::cout << "1) " << another_d.hello(); // 3. lvalue в xvalue std::vector<int> v0{1, 2, 3}; std::vector<int> v2 = static_cast<std::vector<int>&&>(v0); std::cout << "3) после перемещения, v0.size() = " << v0.size() << '\n'; // 4. выражение с отбрасываемым значением static_cast<void>(v2.size()); // 5. инициализирующее преобразование int n = static_cast<int>(3.14); std::cout << "5) n = " << n << '\n'; std::vector<int> v = static_cast<std::vector<int>>(10); std::cout << "5) v.size() = " << v.size() << '\n'; // 6. обратное неявному преобразованию void* nv = &n; int* ni = static_cast<int*>(nv); std::cout << "6) *ni = " << *ni << '\n'; // 7a. scoped enum в int E e = E::TWO; int two = static_cast<int>(e); std::cout << "7a) " << two << '\n'; // 7b. int в enum, enum в другой enum E e2 = static_cast<E>(two); [[maybe_unused]] EU eu = static_cast<EU>(e2); // 7f. указатель на член - приведение вверх int D::*pm = &D::m; std::cout << "7f) " << br.*static_cast<int B::*>(pm) << '\n'; // 7g. void* в любой указатель на объект void* voidp = &e; [[maybe_unused]] std::vector<int>* p = static_cast<std::vector<int>*>(voidp); }
Вывод:
1) Hello world, this is B! 1) Hello world, this is D! 3) after move, v0.size() = 0 5) n = 3 5) v.size() = 10 6) *ni = 3 7a) 2 7f) 42
Отчеты о дефектах
Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C++.
| DR | Применяется к | Поведение в опубликованной версии | Корректное поведение |
|---|---|---|---|
| CWG 137 | C++98 |
константность и волатильность указателей на
void могли быть сняты приведением |
cv-квалификаторы не могут быть
сняты в таких случаях |
| CWG 427 | C++98 | понижающее приведение могло быть неоднозначным с прямой инициализацией | выбирает понижающее приведение в этом случае |
| CWG 439 | C++98 |
при преобразовании "указателя на объект" в "указатель на
void " и обратно в себя, он мог сохранить свое значение только если результирующий тип имеет ту же cv-квалификацию |
cv-квалификация
может отличаться |
| CWG 1094 | C++98 |
преобразование значений с плавающей точкой
в значения перечислений было неопределено |
определено |
| CWG 1320 | C++11 |
преобразование значений ограниченных перечислений
в bool было неопределено |
определено |
| CWG 1412 | C++98 |
результат преобразования из
"указателя на void " в "указатель на объект" был неясен |
прояснено |
| CWG 1447 | C++11 |
преобразование битовых полей в rvalue-ссылки
было неопределено (нельзя связывать ссылки с битовыми полями) |
определено |
| CWG 1766 | C++98 |
преобразование целочисленных или перечислимых значений в перечислимые
значения давало неопределенный результат если expression вне диапазона |
поведение является
неопределенным в этом случае |
| CWG 1832 | C++98 |
преобразование целочисленных или перечислимых значений в
перечислимые значения позволяло target-type быть неполным |
не разрешено |
| CWG 2224 | C++98 |
преобразование члена базового типа класса в
его полный объект производного типа класса было допустимо |
поведение является
неопределенным в этом случае |
| CWG 2254 | C++11 |
объект класса стандартной компоновки без членов данных
был указательно-взаимопреобразуем с его первым базовым классом |
он указательно-взаимопреобразуем
с любым из его базовых классов |
| CWG 2284 | C++11 |
объект нестандартной компоновки union и нестатический член данных
этого объекта не были указательно-взаимопреобразуемы |
они являются |
| CWG 2310 | C++98 |
для преобразований указателей базового в производный класс и
преобразований указателей на члены производного в базовый класс, тип производного класса мог быть неполным |
должен быть полным |
| CWG 2338 | C++11 |
преобразование в типы перечислений с фиксированным базовым типом
приводило к неопределенному поведению если expression вне диапазона |
сначала преобразовать в базовый тип
(без неопределенного поведения) |
| CWG 2499 | C++11 |
класс стандартной компоновки мог иметь не указательно-взаимопреобразуемый
базовый класс, даже если все базовые подобъекты имеют тот же адрес |
он не имеет |
| CWG 2718 | C++98 |
для преобразований ссылок базового в производный класс,
тип производного класса мог быть неполным |
должен быть полным |
| CWG 2882 | C++98 |
было неясно, пытается ли
static_cast
<
void
>
(
expr
)
сформировать неявную последовательность преобразования из expr в void |
не пытается в этом случае |
Ссылки
- Стандарт C++23 (ISO/IEC 14882:2024):
-
- 7.6.1.9 Статическое приведение [expr.static.cast]
- Стандарт C++20 (ISO/IEC 14882:2020):
-
- 7.6.1.8 Статическое приведение [expr.static.cast]
- Стандарт C++17 (ISO/IEC 14882:2017):
-
- 8.2.9 Статическое приведение [expr.static.cast]
- Стандарт C++14 (ISO/IEC 14882:2014):
-
- 5.2.9 Статическое приведение [expr.static.cast]
- Стандарт C++11 (ISO/IEC 14882:2011):
-
- 5.2.9 Статическое приведение [expr.static.cast]
- Стандарт C++98 (ISO/IEC 14882:1998):
-
- 5.2.9 Статическое приведение [expr.static.cast]
- Стандарт C++03 (ISO/IEC 14882:2003):
-
- 5.2.9 Статическое приведение [expr.static.cast]