2011-01-21 3 views
18

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

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

+2

Обратите внимание, что не существует частичная специализация шаблонов функций, только полной специализации. Тем не менее, полная специализация, как правило, представляет собой плохую идею для шаблонов функций, поскольку правила, касающиеся того, что получает специализированное, что перегружено, и то, как разрешение перегрузки решает, что использовать, сложны и запутаны. К счастью, перегрузки и SFINAE (сбой замены не является ошибкой) достаточно. –

+0

Я не получаю предупреждения от Clang 3.8 (или GCC 8.0). Если я удалю шаблон на 'f', я получу его. Есть ли версия '-Wtautological-compare', которая рассматривает шаблонные экземпляры? – user2023370

ответ

22

Вы можете использовать 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 пространствах имен, если ваш компилятор поддерживает C++ 0x или TR1, соответственно. В противном случае Boost имеет реализацию библиотеки типов типов, Boost.TypeTraits. Ускорение внедрения enable_if немного отличается; boost::enable_if_c похож на TR1 и C++ 0x enable_if.

14

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

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; 
} 
+0

+1 за этот последний трюк – TonyK

0

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

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

UPDATE Unsigned флаг

можно реализовать различные варианты реализации для всех неподписанные типы, которые вы хотели бы использовать или добавить флаг 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; 
+0

За исключением того, что он должен работать для всех неподписанных типов: char, short, int, long. –

+0

Ваше решение намного более подробно, чем другие, которые используют «enable_if» (или аналогичную функциональность). –

+1

Ваше решение также кажется единственным, которое может быть реализовано на C++ 03 без использования boost. Это явный плюс в моей книге. Я поднимусь, когда я заставлю его работать;) – Paul

1

Есть ли какой-либо умный способ не проводить сравнение 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 

Также см Comparison is always false due to limited range…