开发者

Partial template specialization based on "signed-ness" of integer type?

Given:

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

When used with an unsigned type generates a warning:

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

Is there any clever way not to do the comparison n >= 0 when T is an unsigned type? I tried adding a partial template specialization:

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

but gcc 4.2.1 doesn't like that. (I didn't think that kind of partial template specialization would 开发者_如何学JAVAbe legal anyway.)


You can use enable_if with the is_unsigned type trait:

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

You can find enable_if and is_unsigned in the std or std::tr1 namespaces if your compiler supports C++0x or TR1, respectively. Otherwise, Boost has an implementation of the type traits library, Boost.TypeTraits. The boost implementation of enable_if is a little different; boost::enable_if_c is similar to the TR1 and C++0x enable_if.


You can take advantage of the wrap-around behavior of unsigned integers.

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)>());
}   

It's important not to say >= 0, to avoid a warning again. The following appears to trick GCC too

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


Starting in c++17 with the introduction of if constexpr you don't even need to provide specializations for this. Unlike a normal if statement the code in the if constexpr will be discarded (not compiled) if the expression is not true. That means you can rewrite your function like

template<typename T>
inline bool f( T n ) 
{
    if constexpr (std::is_unsigned_v<T>)
        return n <= 100;
    else
        return n >= 0 && n <= 100;
}   


Is there any clever way not to do the comparison n >= 0 when T is an unsigned type? I tried adding a partial template specialization:

The optimizer should drop the code for the compare since it detected the condition.

For Clang, add -Wno-tautological-compare to squash the warning. For GCC/G++, add -Wno-type-limits to squash the warning.

If you are using a compiler that support pragma diagnostic {push|pop} you can:

#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

Also see Comparison is always false due to limited range…


You can implement a special template function implementation for unsigned type like:

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

UPDATE Unsigned flag

You can implement different implementations for all unsigned types you'd like to use or add a bool flag like:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜