Есть ли "безопасная" альтернатива static_cast?
Есть ли "безопасная" альтернатива static_cast
в C++11/14 или библиотека, которая реализует эту функциональность?
Под "безопасным" я подразумеваю, что приведение должно разрешать только приведение, которое не теряет точности. Так что актерский состав из int64_t
в int32_t
будет разрешено только если число вписывается в int32_t
и еще сообщается об ошибке.
3 ответа
Там в gsl::narrow
узкий //
narrow<T>(x)
являетсяstatic_cast<T>(x)
еслиstatic_cast<T>(x) == x
или это бросаетnarrowing_error
У вас есть сценарий использования полностью изменен.
Предполагаемое использование static_cast
(и другие приведения в стиле C++) указывают на намерения программиста. Когда ты пишешь auto value = static_cast<int32_t>(value_64);
, вы говорите: "Да, я очень * намерен * уменьшить это значение, возможно, обрезая его, когда я выполняю это назначение". В результате компилятор, который мог бы быть склонен жаловаться на это преобразование при нормальных обстоятельствах (например, если бы вы написали int32_t value = value_64;
вместо этого наблюдает "хорошо, программист сказал мне, что это то, что они намеревались; зачем им врать мне?" и тихо скомпилирует код.
Если вы хотите, чтобы ваш код C++ предупреждал или выдавал ошибку при небезопасных конверсиях, вы должны явно не использовать static_cast
, const_cast
, reinterpret_cast
и пусть компилятор сделает свою работу. У компиляторов есть флаги, которые меняют способ обработки предупреждений int64_t
в int32_t
обычно выдает только предупреждение), поэтому убедитесь, что вы используете правильные флаги, чтобы предупреждения воспринимались как ошибки.
Предполагая, что вопрос касается обнаружения во время компиляции преобразований с потенциально потерями...
Простой инструмент, о котором здесь еще не упоминалось, заключается в том, что инициализация списка не позволяет сужать, поэтому вы можете написать:
void g(int64_t n)
{
int32_t x{n}; // error, narrowing
int32_t g;
g = {n}; // error, narrowing
}
NB. Некоторые компиляторы в своем режиме по умолчанию могут отображать "предупреждение" и продолжать компиляцию для этого плохо сформированного кода, обычно вы можете настроить это поведение с помощью флагов компиляции.
Вы можете создать свой собственный с sfinae. Вот пример:
template <typename T, typename U>
typename std::enable_if<sizeof(T) >= sizeof(U),T>::type
safe_static_cast(U&& val)
{
return static_cast<T>(val);
}
int main()
{
int32_t y = 2;
std::cout << safe_static_cast<int32_t>(y) << std::endl;
std::cout << safe_static_cast<int16_t>(y) << std::endl; // compile error
}
Это скомпилируется, только если размер, который вы приведете, равен>= размеру источника.
Попробуй здесь
Вы можете усложнить это далее, используя numeric_limits для других типов и type_traits.
Обратите внимание, что мое решение является решением во время компиляции, потому что вы спросили о static_cast
где статический здесь относится к "определяется во время компиляции".