2015-11-21 4 views
2

Я пишу функцию void func(K const& val), какая часть класса шаблона.Как передать значения, отличные от std :: numeric_limits <basic_type> :: max(), к функции?

Предположим, я определить объект класса, как foo<unsigned short int> f;, а затем я называю FUNC, как f.func(999999);

Что происходит значение 999999 получает преобразуется в некоторое другое значение, как она сама находится вне диапазона. Как я могу предотвратить это? Есть ли флаг компилятора или какой-либо другой способ в коде, где я могу это предотвратить?

Проверка

if(val > std::numeric_limits<K>::max()) 

внутри func не помогает, так как значение уже конвертированы, когда он становится принят и в то, что находится внутри числового предела.

Например, 999998989898988989999 конвертируется в 11823

Как передать значения больше, чем станд :: numeric_limits :: макс() в функции?

P.S. Я компиляции с помощью GCC (с -std = C++ 11)

+0

В этом случае gcc должен выпустить предупреждение. Установите '-Werror', и вы получите ошибку компиляции при попытке сделать такие вещи. – Rostislav

+1

@Rostislav: И если код не говорит 'f.func (999999); 'but' f.func (x + y); '? –

+0

Связанный вопрос: http://stackoverflow.com/questions/199333/how-to-detect-integer-overflow-in-c-c –

ответ

2

Предполагая, что определение вашего класса foo что-то вроде:

template<typename K> 
class foo { 
public: 
    void func(K const& k) {} 
}; 

Вы могли бы сделать func сам шаблон и проверить пределы перед вызовом фактическая реализация:

#include <iostream> 
#include <limits> 

template<typename K> 
class foo { 
public: 
    template<typename T> 
    std::enable_if_t<std::is_signed<T>::value && !std::is_signed<K>::value> func(T const& t) 
    { 
     if (t < 0 || static_cast<std::make_unsigned_t<T>>(t) > std::numeric_limits<K>::max()) { 
      std::cout << "error\n"; 
      return; 
     } 

     func_impl(t); 
    } 

    template<typename T> 
    std::enable_if_t<!std::is_signed<T>::value && std::is_signed<K>::value> func(T const& t) 
    { 
     if (t > static_cast<std::make_unsigned_t<K>>(std::numeric_limits<K>::max())) { 
      std::cout << "error\n"; 
      return; 
     } 

     func_impl(t); 
    } 

    template<typename T> 
    std::enable_if_t<std::is_signed<T>::value == std::is_signed<K>::value> func(T const& k) 
    { 
     if (k < std::numeric_limits<K>::min() || k > std::numeric_limits<K>::max()) { 
      std::cout << "error\n"; 
      return; 
     } 
     func_impl(k); 
    } 

private: 
    void func_impl(K const& k) 
    { 
     std::cout << "normal\n"; 
    } 
}; 


int main() 
{ 
    foo<char>().func(127); 
    foo<char>().func(127u); 
    foo<char>().func(-128); 
    foo<char>().func(128); 
    foo<char>().func(128u); 
    foo<char>().func(-129); 
    foo<unsigned>().func(-1); 
    foo<int>().func(1u); 
} 

Выход:

нормальный

нормальный

нормальная

ошибка

ошибка

ошибка

ошибки

нормальный

LIVE

Редактировать

Как @BaumMitAugen отметил, boost::numeric_cast, вероятно, будет лучшей альтернативой ручной if с в моей реализации func - он будет бросать исключение, если происходит переполнение или переполнение и вы избежите много шаблонов последней отредактированной версии кода, которая (а) работает, и (б) избегает подписанных/неподписанных предупреждений о сравнении.

+0

Не работает для «underflows». http://coliru.stacked-crooked.com/a/52f7f95ec70c5eb7 Давайте посмотрим, могу ли я сломать переполнение. ;) Но, вероятно, нет, отлично выглядит. –

+0

@BaummitAugen Да, не испытал это слишком много. Подписанные/неподписанные конверсии обязательно должны учитываться и проверяться широко. Подписанный underflow должен быть штраф, хотя :) – Rostislav

+0

Ха, получил ложный положительный результат! http://coliru.stacked-crooked.com/a/25e23233d8bb3b3e Это весело. :) –