派生 class 模板

Derived class template

我对派生的 class 模板有一些疑问。我有这样的基础和派生 class 模板:

// This is base class
class CParameter {
public:
   CParameter(std::string name) : name(name) {}
// virtual ~CParameter() {} // deleted for good design:)

public:
   std::string name;
};

...

// This is derived class
template <typename T>
class CTemplateParameter : public CParameter {
public:
   CTemplateParameter(std::string name) : CParameter(name) {}
public:
   T parameter;
};

并且我声明了一些类型参数并将它们推送到基础 class vector

//Base class parameters
std::vector<CParameter*> parameters; // !
CTemplateParameter<CMatrix4<float>> mat4;
CTemplateParameter<CVector3<float>> vec3;
CTemplateParameter<float> flt;

parameters.push_back(mat4);
parameters.push_back(vec3);
parameters.push_back(flt);

我有模板SetParameter函数:

// This method moved to CParameter base class
template <typename T>
bool SetParameter(const CTemplateParameter<T>& param) {
// switch(typeof(T)) {
// set parameter
if (std::is_same<T, int>::value)
   // gLUniform1i(...)
else if (std::is_same<T, CMatrix4<float>>::value)
   // glUniformMatrix4fv(..)
...

}

所以我的问题:

1) 如何单独设置所有参数?

// Notice this function is not template
void SetAll() {
   for each parameter
      SetParameter(parameter[i])
}

2) 没有枚举,我可以在 运行 时间内获取参数类型并创建类型吗?喜欢:

Pseudo code:
    //get type of parameter[i]
    //create a parameter from
    T type = GetTypeofParameter(parameter[i]);
    CTemplateParameter<type> newType;

3) 我可以得到这样的派生 class 类型或如何转换吗?

CTemplateParameter<void*>* p = dynamic_cast<CTemplateParameter<void*>>(parameters[i]);

非常感谢。

1/ 您应该在 Cparameter 中定义 setParameter 作为抽象方法,并在您的模板 class.

中实现它

2/ 我建议使用克隆(或工厂)方法,按照我在 1/ 中的建议定义。在这种方法中,您可以复制(或创建)您的对象然后定义它。

3/ 不可以。您不能将 CtemplateParameter<float> 转换为 CtemplateParameter<void*>

1) How to set all parameter individual?

除非您知道类型,否则您无法迭代并为所有这些设置值。并且放置大量 dynamic_cast 也不是解决方案,因为它不可扩展。 一种解决方案是保留 std::function 的地图。这些函数不会接受任何参数,return 什么也没有。他们将使用正确的值设置参数。推入向量将是这样的:

std::map<CParameter*, std::function<void()>> mySets;

// ...

mySets.emplace(&parameter, [ObjectThatGiveMeNext, &parameter]() {
    parameter.setParameter(ObjectThatGiveMeNext.get());
});

即使包含参数,它也不是参数的主要容器。它只是为了跟踪哪个参数与哪个函数相关联。

理想的情况是在创建参数时创建此函数,因为您知道那里的参数类型。

另一个解决方案是创建一个虚函数 updateValue,它会用 this.

调用 setParameter

2) Without enum, can I get type of parameter and create a type in run time?

这不太可能,这是您不知道类型的上下文,因此您必须知道类型(switch case)或依赖多态行为。我认为这里最好的是依靠多态行为。

我会为此添加一个虚函数克隆。也许不是著名的直接 clone 函数,而是 return 参数和设置其值的函数的克隆函数。有点像这样:

std::tuple<std::unique_ptr<CParameter>, std::function<void()>> clone();

考虑使用 typedef 或在这种情况下使用,因为类型太长了。

3) Can i get a derived class type like this or how to cast?

不,你不能。您需要将 class 的实例转换为另一个不相关的类型。我不会那样做。相反,将处理特定派生 class 的代码保留在您明确知道类型的地方,并使通用代码保持通用(例如:不要试图知道类型)。这是我现在能告诉你的最好的建议。

我的评论似乎已将 ADesignersEncyclopedia 推离 template/virtual 组合,但没有推向实用的替代方案。最初的问题没有提供足够的信息来决定是否有实际的选择。缺少这样一个实用的替代方案,virtual/template 正确混合(使用 CRTP)而不是完全拒绝它:

在您的目标 class 中,您需要两种形式的 setParameter,这两种形式都不是模板。第一个表单分派到参数 class 内的 setParameter,它分派回目标 class:

中的第二个表单
bool SetParameter(const CParameter& param) {
   return param.SetParameter( *this );
}

第二种形式重载了值类型:

bool SetParameter(int value) {
   // whatever
}
bool SetParameter(CMatrix4<float> const& value) {
   // whatever
}
...

在您的参数库 class 中,您想要 SetParameter 纯虚拟

class CParameter
{
    ...
    virtual bool SetParameter( TargetType& ) const = 0;
    ...
};

那么你需要一个CRTP基础class,它应该来自你的简单基础class:

template<class ActualType>
class CRTPParameter : public CParameter
{
  CRTPParameter(std::string name) : CParameter(name) {}
  ActualType* This() {return static_cast<ActualType*>(this); }
  ActualType const* This() const {return static_cast<ActualType const*>(this); }
  // various things including
  ActualType* clone() const { return new ActualType( *This() ); }
  bool SetParameter( TargetType& target ) const
  { return target.SetParameter( This()->parameter ); }
};

然后你的模板class来自你的CRTPclass

template <typename T>
class CTemplateParameter : public CRTPParameter<CTemplateParameter<T> > {
public:
   typedef CRTPParameter<CTemplateParameter<T> super;
   CTemplateParameter(std::string name) : super(name) {}

如果其他一切都足够简单,那么整个 CRTP 方案可能有点矫枉过正,您可以将 clone 和 SetParameter 从 CRTPParameter 移动到 CTemplateParameter,然后返回到没有 CRTPParameter 的状态。

但根据我对此类结构的经验,CTemplateParameter 中的事情很快就会变得混乱,最好由额外的层来处理。