【问题标题】:Partial class template specialisation for multiple types多种类型的部分类模板特化
【发布时间】:2017-09-20 12:11:50
【问题描述】:

我有一个类,它允许创建一个包含任何类型或类的向量。不过,我想为数字类型添加额外的功能。

template <>
class Vec<double> : public VecBase<double>
{
    //  == METHODS ==
    public:
        //  -- Constructors & Destructors --
        explicit Vec(const unsigned long long t_size);
        virtual ~Vec();

        //  -- Operators --
        friend Vec<double> operator+(const Vec<double>&, const double);

        //  -- Methods --
        double sum();

... etc.

我对类模板进行了部分特化,以允许重载数学运算符以实现双重特化。我现在也想将此特化扩展到 int,但不是复制将 double 替换为 int 的特化,有没有办法将其添加到特化列表中?

也就是说,有没有办法允许:

template<>
class Vec<double (or) int>

干杯!

【问题讨论】:

    标签: c++ templates operator-overloading template-specialization partial-specialization


    【解决方案1】:

    我想你可以使用布尔默认值,比如下面例子中的foo struct

    #include <iostream>
    
    template <typename>
    struct isSpecialType
     { static constexpr bool value { false }; };
    
    template <>
    struct isSpecialType<int>
     { static constexpr bool value { true }; };
    
    template <>
    struct isSpecialType<double>
     { static constexpr bool value { true }; };
    
    template <typename T, bool = isSpecialType<T>::value>
    struct foo;
    
    template <typename T>
    struct foo<T, true>
     { static constexpr bool value { true }; };
    
    template <typename T>
    struct foo<T, false>
     { static constexpr bool value { false }; };
    
    int main()
     {
       std::cout << "- void value:   " << foo<void>::value << std::endl;
       std::cout << "- bool value:   " << foo<bool>::value << std::endl;
       std::cout << "- int value:    " << foo<int>::value << std::endl;
       std::cout << "- double value: " << foo<double>::value << std::endl;
     }
    

    这个想法是定义一种类型特征(isSpecialType)来选择所选类型(int 和 double,在您的示例中),布尔值在通用实现中为 false,@ 987654327@ 在专业领域。

    template <typename>
    struct isSpecialType
     { static constexpr bool value { false }; };
    
    template <>
    struct isSpecialType<int>
     { static constexpr bool value { true }; };
    
    template <>
    struct isSpecialType<double>
     { static constexpr bool value { true }; };
    

    接下来,您必须声明 foo 结构(class Vec,在您的问题中),并带有一个补充 bool 模板值和 isSpecialType&lt;T&gt;::value 默认值

    template <typename T, bool = isSpecialType<T>::value>
    struct foo;
    

    最后,您必须实现foo 的两个部分专用版本:第一个带有布尔值true 的版本

    template <typename T>
    struct foo<T, true>
     { static constexpr bool value { true }; };
    

    对应你的Vec的专用版;具有false 布尔值的那个

    template <typename T>
    struct foo<T, false>
     { static constexpr bool value { false }; }; 
    

    对应于您的Vec 的通用版本。

    还有一点:我的例子是C++11或者更新的代码;如果您想要 C++98 版本,您只需将 bool 值定义为 const(而不是 constexpr)并将它们初始化为 C++98 样式;我是说

     static bool const bool value = true;
    

    而不是

     static constexpr bool value { true };
    

    【讨论】:

      【解决方案2】:

      确实有,但你可能会发现这已经在 http://en.cppreference.com/w/cpp/numeric/valarray 中完成了

      看看 std::enable_if 和 std::is_integral 和 std::is_floating_point。 (copied from cplusplus.com)

      // enable_if example: two ways of using enable_if
      #include <iostream>
      #include <type_traits>
      
      // 1. the return type (bool) is only valid if T is an integral type:
      template <class T>
      typename std::enable_if<std::is_integral<T>::value,bool>::type
        is_odd (T i) {return bool(i%2);}
      
      // 2. the second template argument is only valid if T is an integral type:
      template < class T,
                 class = typename std::enable_if<std::is_integral<T>::value>::type>
      bool is_even (T i) {return !bool(i%2);}
      
      int main() {
      
        short int i = 1;    // code does not compile if type of i is not integral
      
        std::cout << std::boolalpha;
        std::cout << "i is odd: " << is_odd(i) << std::endl;
        std::cout << "i is even: " << is_even(i) << std::endl;
      
        return 0;
      }
      

      【讨论】:

      • 我更喜欢 2),因为它比 1) 更具可读性
      【解决方案3】:

      我对@max66 有同样的想法,但您可以使用辅助函数更轻松地完成此操作。

      #include <iostream>
      #include <type_traits>
      
      // helper
      template <typename ...Ts>
      struct allowed_types
      {
          template <typename T>
          using check = std::disjunction<std::is_same<T, Ts>...>;
      
          template <typename T>
          inline static constexpr bool check_v = check<T>::value;
      };
      
      // usage
      template <typename T, bool = allowed_types<double, float>::check_v<T>>
      struct foo;
      
      template <typename T>
      struct foo<T, true> // for double and float
      {
          inline static constexpr size_t value = 1;
      };
      
      template <typename T>
      struct foo<T, false> // for other types
      {
          inline static constexpr size_t value = 2;
      };
      
      int main()
      {
          std::cout << foo<float>::value << '\n';  // 1
          std::cout << foo<double>::value << '\n'; // 1
          std::cout << foo<int>::value << '\n';    // 2
          std::cout << foo<char>::value << '\n';   // 2
      }
      

      只需放置您需要的任何类型集。 例如:

      template <typename T, bool = allowed_types<char, int, std::vector<int>>::check_v<T>>
      

      编辑:
      如果您需要将您的专业划分为 2 个以上的组,那么您需要使用 enable_if 方法。 使用上面的 helper 可以这样写:

      // default, for any type
      template <typename T, typename = void>
      struct foo
      {
          inline static constexpr size_t value = 1;
      };
      
      // for double and float
      template <typename T>
      struct foo<T, std::enable_if_t<allowed_types<double, float>::check_v<T>>>
      {
          inline static constexpr size_t value = 2;
      };
      
      // for int and char
      template <typename T>
      struct foo<T, std::enable_if_t<allowed_types<int, char>::check_v<T>>>
      {
          inline static constexpr size_t value = 3;
      };
      
      int main()
      {
          std::cout << foo<bool>::value << '\n';   // 1
          std::cout << foo<double>::value << '\n'; // 2
          std::cout << foo<float>::value << '\n';  // 2
          std::cout << foo<int>::value << '\n';    // 3
          std::cout << foo<char>::value << '\n';   // 3
      }
      

      【讨论】:

      • 赞成使用allowed_types的解决方案
      猜你喜欢
      • 2019-08-20
      • 2013-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多