【发布时间】:2016-01-07 15:33:28
【问题描述】:
我将首先提出我的问题,并在下面添加一些更长的解释。我有以下类设计,因为 C++ 不支持虚拟模板方法,所以它不起作用。我很乐意了解实现此行为的替代方案和解决方法。
class LocalParametersBase
{
public:
template<unsigned int target>
virtual double get() const = 0; //<--- not allowed by C++
};
template<unsigned int... params>
class LocalParameters : public LocalParametersBase
{
public:
template<unsigned int target>
double get() const; //<--- this function should be called
};
使用简单的函数参数代替模板参数目前是没有选择的,原因如下:
- 派生类中此方法的实现依赖于一些模板元编程(使用可变类模板参数)。据我所知,不能使用函数参数(即使它们是常量整数类型)作为模板参数。
- 仅使用编译时常量调用该方法。性能在我的应用程序中至关重要,因此我希望从编译时的计算中受益。
- 需要公共基类(为简洁起见,我省略了接口的其余部分)。
非常感谢任何建议。
更新:动机
由于对这种布局的动机有很多疑问,我将尝试用一个简单的例子来解释它。想象一下,您想测量三维空间中的轨迹,在我的具体示例中,这些轨迹是磁场中带电粒子(质量固定)的轨迹。您测量这些轨迹通过近似为 2D 表面的敏感探测器。在轨道与敏感探测器的每个交叉点,轨迹由 5 个参数唯一标识:
- 两个 local 坐标,用于描述轨道与探测器表面 local 坐标系中表面的交点(这就是以这种方式选择类名的原因) ,
- 指定轨迹方向的两个角度,
- 一个包含粒子动量和电荷信息的参数。
因此,一条轨迹完全由一组五个参数(以及相关的表面)识别。但是,单个测量仅包含前两个参数(表面的局部 2D 坐标系中的交点)。这些坐标系可以是不同的类型(卡尔德斯坐标系、圆柱坐标系、球坐标系等)。因此,每次测量都可能会限制全部 5 个参数中的不同参数(或者甚至可能是这些参数的非线性组合)。然而,拟合算法(例如考虑一个简单的 chi2 最小化器)不应该取决于测量的特定类型。它只需要计算残差。看起来像
class LocalParametersBase
{
public:
virtual double getResidual(const AtsVector& fullParameterSet) const = 0;
};
这很好用,因为每个派生类都知道如何将完整的 5 维参数集映射到其局部坐标系上,然后它可以计算残差。我希望这能解释一下为什么我需要一个通用的基类。还有其他与框架相关的原因(例如现有的 I/O 基础设施),您可以将其视为外部约束。
您可能想知道上面的示例不需要我询问的模板化get 方法。只有基类应该向用户公开。因此,如果您有一个 LocalParameterBase 对象列表并且您可以使用它们拟合轨迹,那将会非常混乱。您甚至可以获得测量的局部参数的值。但是您无法访问实际测量值的信息(这使得以前的信息无用)。
我希望这可以阐明我的问题。我感谢到目前为止收到的所有 cmets。
对于我当前的项目,我正在编写一个类,其主要目的是充当固定大小的稀疏向量的包装器。我的类没有存储整个向量(它是某些系统状态的表示),而是将大小减小的向量作为成员变量(= 对应于总参数空间的子域)。我希望下面的插图能让您了解我要描述的内容:
VectorType(5) allParameters = {0.5, 2.1, -3.7, 4, 15/9}; //< full parameter space
VectorType(2) subSpace = {2.1, 4}; //< sub domain only storing parameters with index 1 and 3
为了能够与原始向量建立连接,我需要“存储”复制到“缩短”向量中的索引。这是使用非类型可变参数模板参数实现的。我还需要能够用某个索引查询参数的值。如果此参数未存储在“缩短的”向量中,这将产生编译时错误。我的简化代码如下:
template<unsigned int... index>
class LocalParameters
{
public:
template<unsigned int target>
double get() const;
private:
AtsVectorX m_vValues;
};
LocalParameters<0,1,4> loc;
//< ... do some initialisation ...
loc.get<1>(); //< query value of parameter at index 1
loc.get<2>(); //<-- this should yield a compile time error as the parameter at index 2 is not stored in this local vector class
我设法使用一些简单的模板编程来实现这种行为。但是我的代码的其他部分需要通过一个接口统一处理这些“缩短”的向量。我仍然希望能够通过接口LocalParametersBase访问是否存储了具有特定索引的参数的信息(如果没有我想得到编译时错误),如果是,我想访问的值这个参数。在代码中,这应该类似于
LocalParametersBase* pLoc = new LocalParameters<0,1,3>();
pLoc->get<1>();
【问题讨论】:
-
总体来说,我觉得templates和virutal函数基本是对立的。模板 = 编译时多态性,虚函数 = 运行时多态性。在我看来,试图将两者结合起来听起来很糟糕。如果您确实需要该功能,请考虑将类本身而不是函数模板化。
-
我不太理解你的解释,你为什么要使用继承?您是否正在考虑交换仅在运行时才知道的稀疏向量的不同实现?你说其他函数想要一个统一的接口,但是你展示的实现需要一个统一的接口,还有什么?
-
举个具体的例子,
pLoc->get<1>这行有严重的概念问题。您出于性能原因使用整数模板参数实现 get 并在编译时执行某些操作,但是您引入了一个直到运行时才能解决的间接寻址,而且启动起来也相当昂贵。 -
@DavidHaim 我知道这两个概念有不同的用途。我的问题是我知道 get() 函数只会使用编译时常量调用,我需要与派生类的可变参数模板参数进行比较。据我所知,如果我将
target用作 get 方法的简单函数参数,这是不可能的。使基类模板化不是一种选择,因为例如我需要能够在向量中存储许多不同的实例。 -
@NirFriedman 我的应用程序是一个跟踪软件。一条轨迹可以用 5 个参数来描述,即总相空间。轨迹是从许多测量中重建的,但每次测量仅添加 1 或 2 个坐标的信息。对于轨道重建算法,我不感兴趣单个测量的具体坐标是什么(特别是因为数学总是相同的)。因此我需要一个抽象基类来描述“一些参数的测量”。
标签: c++ templates inheritance variadic-templates