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

后端 未结 5 1002
没有蜡笔的小新
没有蜡笔的小新 2020-12-09 03:37

Given:

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

When used with an unsigned

相关标签:
5条回答
  • 2020-12-09 03:57

    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;
    }   
    
    0 讨论(0)
  • 2020-12-09 04:11

    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 讨论(0)
  • 2020-12-09 04:15

    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.

    0 讨论(0)
  • 2020-12-09 04:15

    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;
    }   
    
    0 讨论(0)
  • 2020-12-09 04:17

    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…

    0 讨论(0)
提交回复
热议问题