В C++ int_cast<функции > зарегистрированного бросает?


Для того, чтобы обнаружить во время выполнения целочисленных задач литья, я создал эту функцию*:

template<typename TTo, typename TFrom>
static inline TTo int_cast(TFrom value)
{
    TTo result = static_cast<TTo>(value);
    if (static_cast<TFrom>(result) != value || (result >= TTo()) != (value >= TFrom()))
    {
        throw std::out_of_range("numeric_cast: value out of range");
    }
    return result;
}

Два вопроса:

  1. Есть какие-то лазейки в этой функции у меня не учитываются (например, неопределенное поведение)?

  2. Что бы быть лучшим способом, чтобы расширить это, чтобы выполнить двойной плавающей и плавающие в интегральных преобразований?

*Примечание: Да, я понимаю, что импульс имеет такие функции. Но я хочу, чтобы мои собственные. :)



2705
15
задан 22 октября 2011 в 01:10 Источник Поделиться
Комментарии
2 ответа


Есть какие-то лазейки в этой функции у меня не учитываются (например, неопределенное поведение)?

Нет. Статическое приведение не приведет к неопределенному поведению.
Если он собирает затем актерский состав хороший (при условии, целое число/типы float).

Хотя некоторые из ваших бросания может привести к конкретной реализации поведения (в зависимости от знака-dness и размер типов).

signed x = int_cast<signed,unsigned>(-1); // implementation defined behavior.

Поскольку это только должно работать на Инт(ы). Я бы тогда сделать это будет ошибка времени компиляции, если вы попытаетесь использовать его с другими типами. Вы также можете быть в состоянии сделать некоторые время компиляции проверка диапазона, когда входные данные являются литералами.

В следующем:

(result >= TTo()) != (value >= TFrom())

Я предполагаю, что это какая-то форма теста signdness (чтобы убедиться, что оба источника и назначения имеют одинаковый знак). Если вы собираетесь сделать это, пожалуйста, комментарий объясняя код точно, как вы думаете, это работает.

Есть число признаков, которые позволяют вытащить signdess и размер типа шаблона из входных/выходных данных. Можно посмотреть на это, чтобы помочь идентифицировать вещи.

8
ответ дан 22 октября 2011 в 07:10 Источник Поделиться

Если вы можете использовать C++11 в вашем приложении, то вы можете использовать enable_if шаблона, чтобы обеспечить несколько перегрузок вашего зарегистрированного сужающее преобразование:

#include <limits>
#include <stdexcept>
#include <type_traits>

template <typename I, typename J>
static typename std::enable_if<std::is_signed<I>::value && std::is_signed<J>::value, I>::type narrow_check(J value) {
if (value < std::numeric_limits<I>::min() || value > std::numeric_limits<I>::max()) {
throw std::out_of_range("out of range");
}
return static_cast<I>(value);
}

template <typename I, typename J>
static typename std::enable_if<std::is_signed<I>::value && std::is_unsigned<J>::value, I>::type narrow_check(J value) {
if (value > static_cast<typename std::make_unsigned<I>::type>(std::numeric_limits<I>::max())) {
throw std::out_of_range("out of range");
}
return static_cast<I>(value);
}

template <typename I, typename J>
static typename std::enable_if<std::is_unsigned<I>::value && std::is_signed<J>::value, I>::type narrow_check(J value) {
if (value < 0 || static_cast<typename std::make_unsigned<J>::type>(value) > std::numeric_limits<I>::max()) {
throw std::out_of_range("out of range");
}
return static_cast<I>(value);
}

template <typename I, typename J>
static typename std::enable_if<std::is_unsigned<I>::value && std::is_unsigned<J>::value, I>::type narrow_check(J value) {
if (value > std::numeric_limits<I>::max()) {
throw std::out_of_range("out of range");
}
return static_cast<I>(value);
}

7
ответ дан 22 мая 2013 в 09:05 Источник Поделиться