Специализация частичного шаблона на основе "подписанности" целочисленного типа?
Дано:
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 не нравится. (Я не думал, что какая-то частичная специализация шаблонов будет законной в любом случае.)
Ответы
Ответ 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;