我有一个包含以下三个类的类层次结构:
template<int pdim >
class Function
{
virtual double operator()( const Point<pdim>& x) const = 0;
};
这是pdim维空间中的函数,返回 double 值。
template<int pdim, int ldim >
class NodeFunction
{
virtual double operator()( const Node<pdim,ldim>& pnode, const Point<ldim>& xLoc) const = 0;
};
它是pdim维空间中节点的ldim维局部空间的函数。
template<int pdim, int ldim, int meshdim >
class PNodeFunction
{
virtual double operator()( const PNode<pdim,ldim,meshdim>& pnode, const Point<ldim>& xLoc) const = 0;
};
此设计的原因1:NodeFunction比Function更通用。它始终可以将本地ldim点映射到pdim点。例如,边缘(具有ldim = 1的节点)将间隔[0,1]映射到pdim维物理空间。这就是每个函数都是NodeFunction的原因。 NodeFunction更通用,因为允许NodeFunction向Node查询属性。
此设计的原因2:PNodeFunction比NodeFunction更通用。每个PNode恰好关联一个节点(反之亦然)。这就是每个PNodeFunction都是NodeFunction的原因。 PNodeFunction更通用,因为它还具有属于Mesh的PNode的所有上下文(因此它知道其所有父级,邻居...)。
摘要:每个
Function<pdim>
都是NodeFunction<pdim, ldim>
的任何参数的ldim
。每个NodeFunction<pdim, ldim>
都是NodeFunction<pdim, ldim, meshdim>
的任何参数的meshdim
。问题:用C++表示的最佳方法是什么,这样我就可以使用
Function
代替NodeFunction
/ PNodeFunction
,从而使代码快速(它是一种高性能的计算代码),从而使该代码适用于模板参数不是完全独立的,而是彼此依赖的:
-
pdim=1,2,3
(主要关注),但如果它也适用于pdim的值(最大为7),那就很好了。-'ldim = 0,1,...,pdim'
-'meshdim = ldim,ldim + 1,...,pdim'
要考虑性能,请注意,在程序中创建了一些函数,但是它们的operator()被多次调用。
变体
我考虑了几种实现此方法的方法(我目前实现了变体1)。我在这里写下来,以便您可以告诉我这些方法的优点和缺点。
变体1
通过助手模板
A<dim> inherits from B<dim,dim2>
实现上述继承Arec<dim,dim2>
。在伪代码中,这是class A<dim> : public Arec<dim,dim>;
class Arec<dim,dim2> : public Arec<dim,dim2-1>, public B<dim,dim2>;
class Arec<dim,0> : public B<dim,dim2>;
这适用于继承NodeFunction的Function和PNodeFunction的NodeFunction。由于NodeFunction从PNodeFunction继承了
O(pdim^2)
的大致时间,它如何扩展?这个巨大的虚拟表不好吗?注意:实际上每个函数也应该继承自
VerboseObject
,这使我可以将有关函数的调试信息打印到例如std::cout
。我实际上是通过从PNodeFunction
继承VerboseObject
来实现的。这将如何影响性能?这应该增加构造函数和打印调试信息的时间,而不是operator()
的时间,对吗?变体2
不要在C++中表达继承,例如
A<dim>
不会从B<dim,dim2>
bur继承,而是有一个将两者转换的函数class AHolder<dim,dim2> : public B<dim, dim> {
}
std::shared_pointer< AHolder<dim,dim2> > interpretAasB( std::shared_pointer< AHolder<dim> >)
[...]
缺点是我不能再使用
Function<dim>
代替NodeFunction<dim>
或PNodeFunction<dim>
。变体3
您首选的实现方式是什么?
最佳答案
我不太了解你的问题。那可能是因为我缺乏对问题域的具体了解。
无论如何,似乎您想生成一个类的层次结构,在底部是Function(派生最多的类),在顶部是PNodeFunction(派生最少的类)。
为此,我只能推荐Alexandrescu的Modern C++设计书,尤其是有关层次生成器的章节。
本书名为Loki,有一个开源库。
Here's the part that might interest you.
采用通用元编程方法可能是最困难的,但我认为,一旦设置,它将带来易用性,并且与虚拟继承相比,可能会提高性能(始终由探查器验证)。
无论如何,我强烈建议不要从Verbose对象继承进行日志记录,而要拥有单独的单例日志记录类。
这样,您就不需要在类层次结构中额外的空间来存储日志记录对象。
您只能从Verbose对象继承最少的派生类,但您的函数类不是日志对象;他们使用了一个日志记录对象(我在这里可能有点学究)。另一个问题是,如果您从该基类继承多次,则最终将获得日志记录对象的多个副本,并且必须使用虚拟继承来解决该问题。