转换为基类时调用的模板超类构造函数

Template superclass constructor called when converting to base

我正在尝试为线性代数程序编写一个实用头文件,它主要用于学习,所以我更关心易用性而不是效率。

无论如何,我的想法是我有一个 Matrix 类型和一个继承自 MatrixVector 类型。因为我想添加一些专门针对3D情况的功能,而不是重写整个class,我还有一个_Vector class,它意味着通用和特殊都可以继承类型。

以下是失败的最小示例: (fails.hpp)

#include <string>

template <int M, int N, typename FloatType = double>
class Matrix {
public:
  inline Matrix() : data{0}{}
protected:
  FloatType data[M * N];
};

template <int DIM, typename FloatType>
class _Vector : public Matrix<DIM, 1, FloatType> {
public:
  template <typename ...FloatTypes>
  inline constexpr _Vector(const FloatTypes... values)
    : Matrix<sizeof...(FloatTypes), 1, FloatType>()
  {
    int i = 0;
    ((Matrix<DIM, 1, FloatType>::data[i++] = values), ...);
  }

  inline FloatType operator [](const int index) {
    return Matrix<DIM, 1, FloatType>::data[index];
  }


  inline operator std::string () const {
    std::string tmp = "[ ";
    for (int i = 0; i < DIM; i++) {
      tmp += std::to_string(Matrix<DIM, 1, FloatType>::data[i]) + " ";
    }
    tmp += "]\n";
    return tmp;
  }
};

template<int DIM, typename FloatType = double>
class Vector : _Vector<DIM, FloatType> {
  template <typename ...FloatTypes>
  inline constexpr Vector(const FloatTypes... values) : _Vector<DIM, FloatType>(values...) {}
};

template <typename ...FloatTypes>
Vector(const FloatTypes...) -> Vector<sizeof...(FloatTypes), std::common_type_t<FloatTypes...>>;

template <typename FloatType>
class Vector<3, FloatType> : public _Vector<3, FloatType> {
public:
  FloatType& x = Matrix<3, 1, FloatType>::data[0];
  FloatType& y = Matrix<3, 1, FloatType>::data[1];
  FloatType& z = Matrix<3, 1, FloatType>::data[2];

  template <typename ...FloatTypes>
  inline constexpr Vector(const FloatTypes... values) : _Vector<3, FloatType>(values...) {}

  // cross product
  inline Vector operator ^(_Vector<3, FloatType>& other) {
    Vector V;
    V.x = y * other[2] - z * other[1];
    V.y = z * other[0] - x * other[2];
    V.z = x * other[1] - y * other[0];
    return V;
  }
};

(main.cpp)

#include <fails.hpp>
//#include <works.hpp>

#include <iostream>

int main() {
  Vector v1 = { 1., 2., 3. };
  Vector v2 = { 3., 2., 1. };

  std::cout << (std::string)(v1 ^ v2);
}

我不明白的是,如果我从 Matrix 类型中删除继承,它会解决问题: (works.hpp)

#include <string>

template <int DIM, typename FloatType>
class _Vector {
public:
  template <typename ...FloatTypes>
  inline constexpr _Vector(const FloatTypes... values)
    {
      int i = 0;
      ((data[i++] = values), ...);
    }

  inline FloatType operator [](const int index) {
    return data[index];
  }


  inline operator std::string () const {
    std::string tmp = "[ ";
    for (int i = 0; i < DIM; i++) {
      tmp += std::to_string(data[i]) + " ";
    }
    tmp += "]\n";
    return tmp;
  }
protected:
  FloatType data[DIM];
};

template<int DIM, typename FloatType = double>
class Vector : _Vector<DIM, FloatType> {
  template <typename ...FloatTypes>
  inline constexpr Vector(const FloatTypes... values) : _Vector<DIM, FloatType>(values...) {}
};

template <typename ...FloatTypes>
Vector(const FloatTypes...) -> Vector<sizeof...(FloatTypes), std::common_type_t<FloatTypes...>>;

template <typename FloatType>
class Vector<3, FloatType> : public _Vector<3, FloatType> {
public:
  FloatType& x = Vector<3, FloatType>::data[0];
  FloatType& y = Vector<3, FloatType>::data[1];
  FloatType& z = Vector<3, FloatType>::data[2];

  template <typename ...FloatTypes>
  inline constexpr Vector(const FloatTypes... values) : _Vector<3, FloatType>(values...) {}

  // cross product
  inline Vector operator ^(_Vector<3, FloatType>& other) {
    Vector V;
    V.x = y * other[2] - z * other[1];
    V.y = z * other[0] - x * other[2];
    V.z = x * other[1] - y * other[0];
    return V;
  }
};

当我用 g++ -I. main.cpp -std=c++17 编译时,我得到这个输出:

n file included from main.cpp:1:
./fails.hpp: In instantiation of ‘constexpr _Vector<DIM, FloatType>::_Vector(const FloatTypes ...) [with FloatTypes = {}; int DIM = 3; FloatType = double]’:
./fails.hpp:54:88:   required from ‘Vector<3, FloatType> Vector<3, FloatType>::operator^(_Vector<3, FloatType>&) [with FloatType = double]’
main.cpp:9:35:   required from here
./fails.hpp:58:12:   in ‘constexpr’ expansion of ‘V.Vector<3, double>::Vector<>()’
./fails.hpp:16:51: error: type ‘Matrix<0, 1, double>’ is not a direct base of ‘_Vector<3, double>’
   16 |     : Matrix<sizeof...(FloatTypes), 1, FloatType>()
      | 

我完全不知道继承是如何改变这种情况的,但现在看来 _Vector class 构造函数被调用是出于某种原因(当时使用了错误的模板参数)。我不知道要搜索什么,所以如果你能解释为什么会导致这个问题,以及一般来说这是什么类型的问题,我将非常感激。 谢谢!

你的_Vector<int DIM, typename FloatType>继承了Matrix<DIM, FloatType>,但是它的构造函数使用sizeof...(FloatTypes)作为Matrix

的第一个模板参数
template <int DIM, typename FloatType>
class _Vector : public Matrix<DIM, 1, FloatType>
 public:
   template <typename ...FloatTypes>
   constexpr _Vector(const FloatTypes... values)
     : Matrix<sizeof...(FloatTypes), 1, FloatType>();
};

这意味着当 DIM 不等于 sizeof...(FloatTypes) 时,您的 _Vector 初始化一个 从它继承的基,您应该将构造函数定义为

template <typename ...FloatTypes>
constexpr _Vector(const FloatTypes... values)
  : Matrix<DIM, 1, FloatType>();