Есть ли "безопасная" альтернатива 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где статический здесь относится к "определяется во время компиляции".

Другие вопросы по тегам