【问题标题】:Class template with enum specific implementation and shared functionality (CRTP)具有枚举特定实现和共享功能 (CRTP) 的类模板
【发布时间】:2018-07-05 12:50:00
【问题描述】:

我想设计一个Matrix 类,它允许指定内存管理的方法,即

Matrix<Allocator::vector, int> mv(2, 2);
Matrix<Allocator::unique_pointer, int> mu(2, 2);

mv(1, 1) = 1;
mu(1, 2) = 1;

尽管内存策略不同,mvmu 仍相互兼容(即当我重载“+”运算符时)。

我已经从Class template specializations with shared functionality 那里找到了非常好的帮助,它对 n 维向量类也有同样的作用。

using dim_t = std::pair<size_t, size_t>;

enum class Allocator { vector, raw_pointer, unique_pointer };

template <typename T>
class MatrixBase {
 public:
  MatrixBase() : MatrixBase(0, 0){};
  MatrixBase(size_t m, size_t n) : dim_(m, n){};

  size_t rows() const;

  virtual T& at(size_t i, size_t j);

 private:
  dim_t dim_;
};

template <typename T>
size_t MatrixBase<T>::rows() const {
  return dim().first;
}

template <Allocator A, typename T>
class Matrix : public MatrixBase<T> {};

template <typename T>
class Matrix<Allocator::vector, T> : public MatrixBase<T> {
 private:
  std::vector<T> data_;
};

template <typename T>
T& Matrix<Allocator::vector, T>::at(size_t i, size_t j) {
  return data_[i * rows() + j];
}

template <typename T>
class Matrix<Allocator::unique_pointer, T> : public MatrixBase<T> {
 private:
  std::unique_ptr<T[]> data_;
};

template <typename T>
T& Matrix<Allocator::unique_pointer, T>::at(size_t i, size_t j) {
  return data_[i * rows() + j];
}

不幸的是编译器抱怨

./matrix.hpp:100:34: error: out-of-line definition of 'at' does not match any declaration in 'Matrix<linalg::Allocator::vector,
      type-parameter-0-0>'
T& Matrix<Allocator::vector, T>::at(size_t i, size_t j) {
  ^
./matrix.hpp:103:20: error: use of undeclared identifier 'rows'
  return data_[i * rows() + j];

我假设错误源于

template <typename T>
class Matrix<Allocator::vector, T> : public MatrixBase<T> {
 private:
  std::vector<T> data_;
};

我该如何解决这个问题?

【问题讨论】:

  • 这是非法返回类型:T&amp; Matrix&lt;Allocator::unique_pointer, T&gt;
  • @Viatorus 已修复
  • @BartekBanachewicz 完成

标签: c++


【解决方案1】:

我已经修复了您的代码。给你:

using dim_t = std::pair<size_t, size_t>;

enum class Allocator { vector, raw_pointer, unique_pointer };

template <typename T>
class MatrixBase {
 public:
  MatrixBase() : MatrixBase(0, 0){};
  MatrixBase(size_t m, size_t n) : dim_(m, n){};

  size_t rows() const;

  virtual T& at(size_t i, size_t j);

 private:
  dim_t dim_;
};

template <typename T>
size_t MatrixBase<T>::rows() const {
  return dim_.first;
}

template <Allocator A, typename T>
class Matrix : public MatrixBase<T> {};

template <typename T>
class Matrix<Allocator::vector, T> : public MatrixBase<T> {
    public:
        T &at(size_t i, size_t j);
    private:
        std::vector<T> data_;
};

template <typename T>
T& Matrix<Allocator::vector, T>::at(size_t i, size_t j) {
  return data_[i * this->rows() + j];
}

template <typename T>
class Matrix<Allocator::unique_pointer, T> : public MatrixBase<T> {
    public:
        T &at(size_t i, size_t j);
    private:
        std::unique_ptr<T[]> data_;
};

template <typename T>
T& Matrix<Allocator::unique_pointer, T>::at(size_t i, size_t j) {
  return data_[i * this->rows() + j];
}

首先,如果你重写了一个方法,你必须在派生类中声明它。其次,rows()函数默认无法解析为成员。

【讨论】:

【解决方案2】:

将定义移到里面就可以解决问题。这个问题是由于范围界定造成的。

template <typename T>
class Matrix<Allocator::vector, T> : public MatrixBase<T> {
public: // or private:
    T& at(size_t i, size_t j) {
        return data_[i * MatrixBase<T>::rows() + j];
    }
private:
    std::vector<T> data_;
};

考虑以下示例

class P {
    public:
        virtual int test();
};

class C : public P {
};

int C::P:: test() { // if you omit P, it will not compile
    return 21;
}

或者您可以在C 中重新声明它,这样它就会在C 的范围内。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 2011-10-24
    相关资源
    最近更新 更多