基于整数类型“signed-ness”的部分模板专业化?

时间:2011-01-21 17:56:22

标签: c++ templates specialization

假设:

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 >= 0T类型时,是否有任何聪明的方法不进行比较unsigned?我尝试添加部分模板专业化:

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

但gcc 4.2.1不喜欢这样。 (我不认为 那种部分模板专业化无论如何都是合法的。)

5 个答案:

答案 0 :(得分:24)

您可以将enable_ifis_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;  
}

如果编译器分别支持C ++ 0x或TR1,则可以在enable_ifis_unsigned命名空间中找到stdstd::tr1。否则,Boost具有类型特征库Boost.TypeTraits的实现。 enable_if的推动实施略有不同; boost::enable_if_c类似于TR1和C ++ 0x enable_if

答案 1 :(得分:15)

您可以利用无符号整数的环绕行为。

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

答案 2 :(得分:3)

开始,开始引入if constexpr,您甚至不需要为此专门提供专业知识。与普通的if语句不同,如果表达式不为真,if constexpr中的代码将被丢弃(不编译)。这意味着您可以像这样重写函数

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

答案 3 :(得分:1)

  

当T是无符号类型时,有没有聪明的方法不进行比较n&gt; = 0?我尝试添加部分模板专业化:

优化器应该删除比较代码,因为它检测到了条件。

对于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…

答案 4 :(得分:0)

您可以为unsigned类型实现特殊的模板函数实现,如:

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

更新无符号标记

您可以为要使用的所有无符号类型实现不同的实现,或添加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;