Return 专用模板的协变类型 class

Return covariant type of specialized template class

我有以下 class 层次结构:

template<typename T>
class GridMetric{
  virtual GridMetric* getNeighbors(T value) = 0;
};

template<size_t N, typename T, typename Derived>
class MatrixBase : public GridMetric<T>{
  virtual MatrixBase<N,T,Derived>* getNeighbors(T value){return nullptr;}
};

template<size_t N, typename T>
class MatrixND : public MatrixBase<N,T,MatrixND<N,T>>{
  virtual MatrixND<2,T>* getNeighbors(T value){ /* ... */}
};

template<typename T>
class MatrixND<2,T> : public MatrixBase<2,T,MatrixND<2,T>>{
  virtual MatrixND<2,T>* getNeighbors(T value){ /* ... */}
};

template<typename T>
class Vector : public GridMetric<T>{
  virtual MatrixND<2,T>* getNeighbors(T value){ /* ... */}
};

所以我的抽象 class GridMetric 有两个派生的 classes,Vector 和 MatrixBase。我的 Matrix Base class 具有派生的 crtp 样式 class MatrixND 并且有一个专门化的 MatrixND 与 N=2.

每个 class 都应有一个虚拟函数 getNeighbors 到 return MatrixND<2,T> 指针。

一切正常,除了 MatrixND class 抱怨 MatrixND<2,T> 是无效协变 return 类型:

error: invalid covariant return type for ‘MatrixND<2ul, T>* MatrixND<N, T>::getNeighbors(T&) [with long unsigned int N = 3ul; T = double]’
  virtual MatrixND<2,T>* getNeighbors(T& in){

我的第一个问题是为什么以及我该如何处理?由于 MatrixND<2,T> 继承自 MatrixBase!

我的第二个问题:是不是设计不好,因为我总是 return 原始指针?我读了表达式 return new obj.. 很多,但也认为这显然是糟糕的设计。是否有其他可能实现同样的目标?

编辑: 所以,过了一段时间,我意识到,原来的计划是行不通的,我通过模板化 [=32] 找到了一个更简单的解决方案=],我想在其中使用那些 classes.

无论如何,问题来了,为什么专用 MatrixND class 不能是通用 MatrixND class 中的协变 return 类型。我没有找到任何说不允许的内容。

  • MatrixND<2,T>,基本情况,无需解释。
  • Vector<T> 继承自 GridMetric<T>,因此从 GridMetric<T> 派生的任何内容(包括此处的 MatrixND<2,T>)都可以。

但是,一般形式 MatrixND<N,T> (N != 2) 继承自 MatrixBase<N,T,MatrixND<N,T>>,它将虚函数重新定义为:

virtual MatrixBase<N,T,Derived>* getNeighbors(T value){return nullptr;}

这迫使 MatrixND<N,T> 的 return 类型现在(至少)派生自 MatrixBase<N,T,MatrixND<N,T>>
不是来自 GridMetric<T>(至于 Vector<T>)或 MatrixBase<2,T,MatrixND<2,T>>(至于专业化 MatrixND<2,T>),而是:MatrixBase<N,T,MatrixND<N,T>>,与 (N ! = 2).

为什么这不是协变 return 类型?因为当 N != 2.

MatrixND<2,T> 不继承自 MatrixBase<N,T,MatrixND<N,T>>

要么删除 MatrixBase<N,T,MatrixND<N,T>> 中的函数重新定义,要么将其 return 类型更改为 GridMetric<T>,这将起作用(因为 MatrixND<2,T> 继承自 GridMetric<T> ).