C++ 当使用带有多个模板参数的CRTP时,如何声明模板默认值?
我想做:C++ 当使用带有多个模板参数的CRTP时,如何声明模板默认值?,c++,templates,c++11,crtp,C++,Templates,C++11,Crtp,我想做: template <class Derived=BattleData> class BattleData : public BattleCommandManager<Derived> { }; 但是我得到了 错误:“第二行的模板参数编号错误,带有 作战数据 我真的看不到解决这个问题的办法 编辑: 我这样做的原因是因为我希望能够直接使用BattleData作为类,但我也希望能够将其子类化,在这种情况下,我必须将派生的类指定为第二个模板参数 例如,假设我的Batt
template <class Derived=BattleData>
class BattleData : public BattleCommandManager<Derived> {
};
但是我得到了
错误:“第二行的模板参数编号错误,带有
作战数据
我真的看不到解决这个问题的办法
编辑:
我这样做的原因是因为我希望能够直接使用BattleData
作为类
,但我也希望能够将其子类化,在这种情况下,我必须将派生的类
指定为第二个模板
参数
例如,假设我的BattleData
类的语料库是:
template <class Derived> class BattleData: public BaseClass<Derived> {
void foo1(){};
void foo2(){};
void foo3(){};
}
如果不能使用默认参数,我甚至无法执行以下操作:
BattleData<BattleData> *x = new BattleData<BattleData>(...);
BattleData*x=新的作战数据(…);
一方面,在BattleData类中没有虚拟化函数的原因是没有虚拟函数的好处。另一个对我不起作用的原因是,父CRTP类中的一个只有在派生类型中存在函数时才会调用函数(使用decltype(派生::函数)
并启用if-like结构),否则返回默认行为。因为可能存在大量具有特定设计模式的函数(如CRTP,它读取具有许多不同案例的协议,并且仅当派生类指定相应函数时才以特定方式处理案例,否则只需在不处理的情况下传输它)
因此,这些函数可以出现在
SubBattleData
中,而不是BattleData
,但是如果实例化,这两个类都可以正常工作,但是实例化BattleData
是不可能的。我看不出您想做什么。这两个类有什么问题吗
template <class T=DataContainer>
class BattleData : public BattleCommandManager< BattleData<T> > {
};
我不知道你能做到这一点。另一个
方法是使用策略类而不是CRTP
与继承兼容,您可以实现类似的行为
template<typename Policy>
struct BattleCmdManager : public Policy {
using Policy::foo;
};
template<typename T>
struct BattleData {
// ...
protected:
void foo();
};
struct BattleData2 : public BattleData<int {
// ...
protected:
void foo();
};
模板
结构管理器:公共策略{
使用Policy::foo;
};
模板
结构作战数据{
// ...
受保护的:
void foo();
};
struct BattleData2:public BattleData第二个模板参数不能使用空类吗
template <class T=DataContainer, class Derived=BattleData<T, Empty> >
class BattleData : public BattleCommandManager<Derived> {
};
模板
类BattleData:公共BattleCommandManager{
};
以下是我解决问题的方法:
template <class Derived> class BattleDataInh: public BaseClass<Derived> {
void foo1(){};
void foo2(){};
void foo3(){};
};
template class SubBattleData: public BattleDataInh<SubBattleData> {
void foo1(){};
};
class BattleData : public BattleDataInh<BattleData> {
};
模板类BattleDataInh:公共基类{
void foo1(){};
void foo2(){};
void foo3(){};
};
模板类SubBattleData:public BattleDataInh{
void foo1(){};
};
类别BattleData:公共BattleDataInh{
};
这样,我也可以添加任何其他模板参数。解决方案一直在我眼前,但我没有看到它…你应该能够比上面更自然地完成你的原始设计目标。你不能清楚地使用实际派生的typename作为默认值,因为你真正想写的是以下:
template <class Derived=BattleData <BattleData <BattleData <...>>>
class BattleData : public BattleCommandManager<Derived> {
};
模板::类型>
{
};
免责声明:我没有编译上述内容。只有当他想使用默认类型时,这才是等效的。但是如果他想提供第二个模板参数呢?@Nawaz这是我答案的一部分:你不能调用它(或者至少使用它)作为CRTP,如果他提供了与实际派生类不同的第二个模板参数。所有涉及的类都在继承链中。但从您的示例中,我看到了Policy的用法(我也在使用它来指定一些事情的行为),我只是从未想过将其用作“实现”类。我会试试看,确保它能用。试过之后,我发现了几个问题。首先,我必须使用typedef基类数据。如果BattleDataImpl需要一个额外的模板参数,这将不起作用,因为模板别名尚未实现。其次,CRTP调用主要来自其他策略,因此由于它们都是BaseClass
的父类,因此我必须使用dynamic\u cast(this)
而不是static\u cast
。模板别名问题很容易解决。在上面寻找合适的问题。我不理解您的第二个问题,因为我不明白在使用策略时如何需要强制转换。抱歉。子类化:你是指虚拟函数还是静态多态性?我试着自己弄明白你想要做什么,并且做对了。看看我的建议。这是行不通的,因为当时还不知道战斗数据。谢谢!非常感谢你!以这种方式欺骗编译器是非常复杂的,我不必更改任何剩余的代码…:)@pmr,正向声明模板类数据代码>解决了您提到的问题,实际上,从头开始。代码编译得很好,但是当我实例化它时,我确实得到了一个无效的静态抛出错误。这是因为CRTP试图将this
转换为BattleData
,而派生类实际上是BattleData
。是的,这确实有效。您甚至可以在BattleData
中省略
。
template<typename Policy>
struct BattleCmdManager : public Policy {
using Policy::foo;
};
template<typename T>
struct BattleData {
// ...
protected:
void foo();
};
struct BattleData2 : public BattleData<int {
// ...
protected:
void foo();
};
template <class T=DataContainer, class Derived=BattleData<T, Empty> >
class BattleData : public BattleCommandManager<Derived> {
};
template <class Derived> class BattleDataInh: public BaseClass<Derived> {
void foo1(){};
void foo2(){};
void foo3(){};
};
template class SubBattleData: public BattleDataInh<SubBattleData> {
void foo1(){};
};
class BattleData : public BattleDataInh<BattleData> {
};
template <class Derived=BattleData <BattleData <BattleData <...>>>
class BattleData : public BattleCommandManager<Derived> {
};
template <typename T = void>
class BattleData : public BattleCommandManager <
typename std::conditional <
std::is_same <T, void>::value,
BattleData <void>,
T
>::type>
{
};