我对派生类模板有一些疑问。我有这样的基类和派生类模板:
// 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;
};
我声明了一些类型参数,将它们推送到基类向量
//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)我可以获得这样的派生类类型或如何投射吗?
CTemplateParameter<void*>* p = dynamic_cast<CTemplateParameter<void*>>(parameters[i]);
非常感谢。
答案 0 :(得分:1)
1 /
您应该在setParameter
中将Cparameter
定义为抽象方法,并在模板类中实现它。
2 / 我建议使用克隆(或工厂)方法,如我在1 /中建议的那样定义。在此方法中,您可以复制(或创建)对象,然后定义它。
3 /
不可以。您无法将CtemplateParameter<float>
投射到CtemplateParameter<void*>
答案 1 :(得分:1)
1)如何设置所有参数个人?
除非您知道类型,否则不能迭代并设置所有值的值。并且放置大量的dynamic_cast也不是解决方案,因为它不可扩展。
一种解决方案是保留std::function
的地图。这些函数不会接受任何参数并且不返回任何内容。他们将使用正确的值设置参数。推入向量将是这样的:
std::map<CParameter*, std::function<void()>> mySets;
// ...
mySets.emplace(¶meter, [ObjectThatGiveMeNext, ¶meter]() {
parameter.setParameter(ObjectThatGiveMeNext.get());
});
即使您包含参数,它也不是参数的主要容器。它只是跟踪哪个参数与哪个函数相关联。
理想的做法是在创建参数时创建此函数,因为您知道参数的类型。
另一种解决方案是创建一个虚拟函数updateValue
,使用setParameter
调用this
。
2)没有枚举,我可以获取参数类型并在运行时创建一个类型吗?
这不太可能是你不知道类型的上下文,所以你必须知道类型(切换案例)或依赖多态行为。我认为这里最好的是依靠多态行为。
我会为此添加一个虚拟函数克隆。也许不是着名的直接clone
函数,而是一个克隆函数,它返回参数和函数来设置它的值。有点像这样:
std::tuple<std::unique_ptr<CParameter>, std::function<void()>> clone();
考虑一个typedef或在这种情况下使用,因为类型是loooooong。
3)我可以获得这样的派生类类型或如何投射吗?
不,你不能。您需要将类的实例转换为另一个类,而不是相关类型。我不会这样做。相反,保持您的代码处理您的特定派生类,您明确知道类型并保持通用代码通用(例如:不试图知道类型)。这是我现在可以告诉你的最佳建议。
答案 2 :(得分:1)
我的评论似乎推动ADesignersEncyclopedia远离模板/虚拟混合,而不是实用的替代方案。最初的问题没有提供足够的信息来决定是否有一个实际的选择。缺乏这样一个实用的替代方案,虚拟/模板混合正确(使用CRTP)而不是完全拒绝它:
在目标类中,您需要两种形式的setParameter
,两种形式都不是模板。第一个表单调度到参数类中的setParameter
,该类调度回目标类中的第二个表单:
bool SetParameter(const CParameter& param) {
return param.SetParameter( *this );
}
第二种形式在值类型上重载:
bool SetParameter(int value) {
// whatever
}
bool SetParameter(CMatrix4<float> const& value) {
// whatever
}
...
在参数基类中,您需要SetParameter pure virtual
class CParameter
{
...
virtual bool SetParameter( TargetType& ) const = 0;
...
};
然后你需要一个CRTP基类,它应该从你的简单基类派生出来:
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 ); }
};
然后您的模板类派生自您的CRTP类
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中的事情很快就会被额外层处理得最好。