Если необходимо использовать приведение типа, используйте именованное приведение
Причина
Читаемость. Предотвращение ошибок. Именованные приведения более конкретны, чем приведения в стиле C или функциональные приведения, и позволяют компилятору обнаруживать ряд ошибок.
Именованные приведения:
static_castconst_castreinterpret_castdynamic_caststd::move//move(x)— это rvalue-ссылка наxstd::forward//forward<T>(x)— rvalue- или lvalue-ссылка наxв зависимости отTgsl::narrow_cast//narrow_cast<T>(x)— этоstatic_cast<T>(x)gsl::narrow//narrow<T>(x)— этоstatic_cast<T>(x), еслиstatic_cast<T>(x) == x, иначе бросаетnarrowing_error
Пример
class B { /* ... */ };
class D { /* ... */ };
template<typename D> D* upcast(B* pb)
{
D* pd0 = pb; // ошибка: нет неявного преобразования из B* в D*
D* pd1 = (D*)pb; // допустимо, но что именно делается?
D* pd2 = static_cast<D*>(pb); // ошибка: D не является производным от B
D* pd3 = reinterpret_cast<D*>(pb); // OK: на ваш страх и риск!
D* pd4 = dynamic_cast<D*>(pb); // OK: вернёт nullptr
// ...
}
Пример взят из реальных ошибок, когда D когда-то наследовал от B, но кто-то переработал иерархию. Приведение в стиле C опасно, потому что может выполнить преобразование любого рода, лишая нас защиты от ошибок (текущих и будущих).
Примечание
При преобразовании между типами без потери информации (например, из float в double или из int32 в int64) вместо этого можно использовать инициализацию через фигурные скобки.
double d {some_float};
int64_t i {some_int32};
Это явно указывает на намеренное преобразование типа и предотвращает преобразования между типами, которые могут привести к потере точности. (Попытка инициализировать float из double таким способом является ошибкой компиляции.)
Примечание
reinterpret_cast может быть необходим, но существенные его применения (например, преобразование адреса памяти в указатель) небезопасны с точки зрения типов:
auto p = reinterpret_cast<Device_register>(0x800); // по сути небезопасно
Контроль
- Отмечать все приведения в стиле C, включая приведение к
void. - Отмечать приведения в функциональном стиле вида
Type(value). Используйте вместо этогоType{value}, которое не допускает сужения. (Смотрите ES.64.) - Профиль типов запрещает
reinterpret_cast. - Профиль типов предупреждает при использовании
static_castмежду арифметическими типами.