派生 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(¶meter, [ObjectThatGiveMeNext, ¶meter]() {
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 中的事情很快就会变得混乱,最好由额外的层来处理。
我对派生的 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(¶meter, [ObjectThatGiveMeNext, ¶meter]() {
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 中的事情很快就会变得混乱,最好由额外的层来处理。