【问题标题】:Can you instantiate the unspecialized version of a template and inherit from it inside the specialization?您可以实例化模板的非专业版本并在专业化中继承它吗?
【发布时间】:2020-05-24 20:47:10
【问题描述】:

我正在尝试将Vector 定义为行/列MatrixVector 需要一些Matrix 没有的方法,所以我专门化了Matrix

template<typename T, unsigned N, unsigned M>
struct Matrix {
    T data[N][M];
};

template <typename T, unsigned N>
struct Matrix<T, N, 1> : public Matrix<T, N, 1> {
    T at(unsigned index) {
        return data[index][0];
    }
};

template <typename T, unsigned N>
using Vector = Matrix<T, N, 1>;

此代码无法编译,因为特化是递归类型。我在这里想要继承的原因是这样我就可以将Matrix的所有内容都包含到专业化中,而无需复制和粘贴。

有没有办法可以实例化原始的Matrix 并从中继承?如果有,我的类型会变成非递归的吗?

想到的另一种解决此问题的方法是将常规Matrix 的内容简单地#include 放入初始定义和所有特化中。但这远非惯用语。

【问题讨论】:

    标签: c++ templates matrix specialization


    【解决方案1】:

    这是一种方法:

    template<typename T, unsigned N, unsigned M>
    struct Matrix {
        T data[N][M];
    };
    
    template<typename T, unsigned N>
    struct MatrixTN : Matrix <T, N, 1> {
        T at(unsigned index) {
            return this->data[index][0];
        }
    };
    
    template<typename T, unsigned N>
    using Vector = MatrixTN <T, N>;
    

    请注意,this-&gt;data 需要将 data 的评估延迟到模板查找的第二阶段。

    Live demo

    【讨论】:

    • 这种情况下VectorMatrixTN没有区别,所以可以写成Vector : Matrix&lt;T, N, 1&gt;
    • @J.Schultke 我想是的。
    【解决方案2】:

    在 C++20 中,您可以使用 requires 来丢弃方法:

    template<typename T, unsigned N, unsigned M>
    struct Matrix {
        T data[N][M];
    
        T at(unsigned index) requires (M == 1) {
            return data[index][0];
        }
    };
    

    在以前的标准中,您可以改用 SFINAE。

    【讨论】:

      【解决方案3】:

      您可以使用SFINAE 禁用方法。必须有模板方法的模板参数依赖于类模板参数。

      C++11:

      #include <type_traits>
      
      template<typename T, unsigned N, unsigned M=1>
      struct Matrix 
      {
          T data[N][M];
      
          template<typename V = T>
          typename std::enable_if<M == 1, V>::type at(unsigned index)
          {
              return data[index][0];
          }
      };
      
      template <typename T, unsigned N>
      using Vector = Matrix<T, N, 1>;
      
      int main()
      {
          Matrix<int, 2, 3> m;
          Vector<int, 5> v;
      
          // m.at(0); 
          v.at(1);
      }
      

      C++14:

      #include <type_traits>
      
      template<typename T, unsigned N, unsigned M=1>
      struct Matrix 
      {
          T data[N][M];
      
          template<typename V = T>
          std::enable_if_t<M == 1, V> at(unsigned index)
          {
              return data[index][0];
          }
      };
      
      template <typename T, unsigned N>
      using Vector = Matrix<T, N, 1>;
      
      int main()
      {
          Matrix<int, 2, 3> m;
          Vector<int, 5> v;
      
          // m.at(0); 
          v.at(1);
      }
      

      C++20(感谢 Jarod42):

      template<typename T, unsigned N, unsigned M = 1>
      struct Matrix 
      {
          T data[N][M];
      
          T at(unsigned index) requires (M == 1)
          {
              return data[index][0];
          }
      };
      
      template <typename T, unsigned N>
      using Vector = Matrix<T, N, 1>;
      
      int main()
      {
          Matrix<int, 2, 3> m;
          Vector<int, 5> v;
      
          // m.at(0); 
          v.at(1);
      }
      

      godbolt

      【讨论】:

      • 我从来没有让 SFINAE 解决方案自己工作,所以我认为这是不可能的。显然不是。谢谢,我接受了这个答案,因为它更优雅,而且VectorMatrix 的类型完全相同,而不是派生类型。
      猜你喜欢
      • 2010-12-26
      • 1970-01-01
      • 2015-08-01
      • 2011-10-27
      • 2020-07-18
      • 2021-04-12
      • 2018-09-28
      • 1970-01-01
      • 2018-03-17
      相关资源
      最近更新 更多