Подтвердить что ты не робот

Специализация частичного шаблона на основе "подписанности" целочисленного типа?

Дано:

template<typename T>
inline bool f( T n ) {
  return n >= 0 && n <= 100;
}   

При использовании с типом unsigned генерируется предупреждение:

unsigned n;
f( n ); // warning: comparison n >= 0 is always true

Есть ли какой-либо умный способ не сравнивать n >= 0, когда T является типом unsigned? Я попытался добавить специализацию частичного шаблона:

template<typename T>
inline bool f( unsigned T n ) {
  return n <= 100;
}   

но gcc 4.2.1 не нравится. (Я не думал, что какая-то частичная специализация шаблонов будет законной в любом случае.)

4b9b3361

Ответ 1

Вы можете использовать enable_if с типом типа is_unsigned:

template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, bool>::type f(T n)
{
    return n <= 100;  
}

template <typename T>
typename std::enable_if<!std::is_unsigned<T>::value, bool>::type f(T n)
{
    return n >= 0 && n <= 100;  
}

Вы можете найти enable_if и is_unsigned в пространствах имен std или std::tr1, если ваш компилятор поддерживает С++ 0x или TR1, соответственно. В противном случае Boost имеет реализацию библиотеки типов типов, Boost.TypeTraits. Повышение уровня enable_if немного отличается; boost::enable_if_c похож на TR1 и С++ 0x enable_if.

Ответ 2

Вы можете воспользоваться обходным поведением беззнаковых целых чисел.

template<bool> struct bool_ { };

template<typename T>
inline bool f( T n, bool_<false> ) {
  return n >= 0 && n <= 100;
}

template<typename T>
inline bool f( T n, bool_<true> ) {
  return n <= 100;
}

template<typename T>
inline bool f( T n ) {
  return f(n, bool_<(static_cast<T>(-1) > 0)>());
}   

Важно не говорить >= 0, чтобы избежать предупреждения снова. Следующее, похоже, тоже обманывает GCC

template<typename T>
inline bool f( T n ) {
  return (n == 0 || n > 0) && n <= 100;
}   

Ответ 3

Есть ли какой-нибудь умный способ не проводить сравнение n >= 0, когда T является неподписанным типом? Я попытался добавить специализацию частичного шаблона:

Оптимизатор должен удалить код для сравнения, так как он обнаружил условие.

Для Clang добавьте -Wno-tautological-compare, чтобы выжать предупреждение. Для GCC/g++ добавьте -Wno-type-limits, чтобы раздавить предупреждение.

Если вы используете компилятор, поддерживающий pragma diagnostic {push|pop}, вы можете:

#if (GCC_VERSION >= 40600) || (LLVM_CLANG_VERSION >= 10700) || (APPLE_CLANG_VERSION >= 20000)
# define GCC_DIAGNOSTIC_AVAILABLE 1
#endif    

#if MSC_VERSION
# pragma warning(push)
# pragma warning(disable: 4389)
#endif

#if GCC_DIAGNOSTIC_AVAILABLE
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wsign-compare"
# if (LLVM_CLANG_VERSION >= 20800) || (APPLE_CLANG_VERSION >= 30000)
#  pragma GCC diagnostic ignored "-Wtautological-compare"
# elif (GCC_VERSION >= 40300)
#  pragma GCC diagnostic ignored "-Wtype-limits"
# endif
#endif

template<typename T>
inline bool f( T n ) {
  return n >= 0 && n <= 100;
}

#if GCC_DIAGNOSTIC_AVAILABLE
# pragma GCC diagnostic pop
#endif

#if MSC_VERSION
# pragma warning(pop)
#endif

Также см. Сравнение всегда неверно из-за ограниченного диапазона...

Ответ 4

Вы можете реализовать специальную реализацию функции шаблона для типа unsigned типа:

template<class T> bool f(T val);
template<> bool f<unsigned>(unsigned val);

UPDATE Неподписанный флаг

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

template <class T, bool U> bool f(T val)
{
        if (U)
                return val <= 100;
        else
                return (val >=0 ) && (val <= 100);
}

...

cout << f<int, false>(1) << endl;
cout << f<int, false>(-1) << endl;
cout << f<char, true>(10) << endl;