dee*_*146 12 c++ static templates
有没有人知道一种方法,使派生类自动实例化一个模板类型的静态变量(这要么不需要派生类的编写器,或强迫他调用这个静态方法,以使派生类定义有效).
这可能是不可能理解的,我会尝试更好地定义它.
基本上我有一个全局工厂类,带有一个名为registerType的模板化函数.对于从Entity派生的每个类,我需要使用派生类型的模板参数调用此函数.目前,我必须在某个init函数中手动执行此操作,这会导致对此函数的大量调用,这违反了我的模板原则.
所以我有这个:
class Factory
{
template <typename EntityType>
registerEntityType();
};
void someInitFunction()
{
/// All of these are derived from Entity
gFactory.registerEntityType<EntityType1>();
gFactory.registerEntityType<EntityType2>();
gFactory.registerEntityType<EntityType3>();
/// and so on
}
Run Code Online (Sandbox Code Playgroud)
而我宁愿这样:
class Factory
{
template <typename EntityType>
registerEntityType();
};
class Entity // Abstract
{
/// This function should be called automatically with the derived
/// type as a parameter
SomeStaticConstructor<MDerivedType>()
{
gFactory.registerEntityType<MDerivedType>();
}
};
Run Code Online (Sandbox Code Playgroud)
编辑:这是不起作用的静态重复模板代码:
这是我的基类,以及用于自动注册东西的类
template <typename DerivedType>
class Registrar
{
public:
Registrar();
void check();
};
template <typename Product, typename DerivedType>
class AbstractFactory: public AbstractFactoryBase<Product>
{
public:
AbstractFactory();
~AbstractFactory();
private:
static Registrar<DerivedType> registrar;
};
Run Code Online (Sandbox Code Playgroud)
注册商的构造函数
template <typename DerivedType>
Registrar<DerivedType>::Registrar()
{
std::cout << DerivedType::name() << " initialisation" << std::endl;
g_AbstractFactories.registerFactoryType<DerivedType>(DerivedType::name());
}
Run Code Online (Sandbox Code Playgroud)
和派生类型
class CrateFactory : public AbstractFactory<Entity, CrateFactory>
{
public:
CrateFactory(FactoryLoader* loader);
virtual ~CrateFactory();
Entity* useFactory(FactoryParameters* parameters);
static std::string name()
{
return "CrateFactory";
}
Run Code Online (Sandbox Code Playgroud)
Xeo*_*Xeo 10
我建议使用CTRP -backed方法:
// Entity.h
class EntityBase
{ // abstract
};
template<class Derived>
class Entity
: public EntityBase
{ // also abstract thanks to the base
static char _enforce_registration; // will be instantiated upon program start
};
// your actual types in other headers
class EntityType1
: public Entity<EntityType1>
{ // automatic registration thanks to the _enforce_registration of the base
// ...
};
// Entity.cpp
#include "Entity.h"
template<class T>
char RegisterType(){
GetGlobalFactory().registerEntityType<T>();
return 0; // doesn't matter, never used.
}
template<class Derived>
char Entity<Derived>::_enforce_registration = RegisterType<Derived>();
Run Code Online (Sandbox Code Playgroud)
虽然,如您所见,您现在需要让您的工厂通过一个GetGlobalFactory函数,该函数延迟初始化工厂以确保在强制注册发生之前已初始化它:
Factory& GetGlobalFactory(){
static Factory _factory;
return _factory;
}
Run Code Online (Sandbox Code Playgroud)
您可以使用混合和CRTP获得所需的内容.
但首先,您需要处理"初始化顺序"问题.为了确保在gFactory尝试使用它之前存在,你真的需要使它成为一个合适的"单例"类,如下所示:
class Factory {
public:
static Factory &getFactory() { static Factory f; return f; }
template <typename EntityType>
void registerEntityType() { ... }
};
Run Code Online (Sandbox Code Playgroud)
然后"混合"看起来像这样:
template <typename T>
class EntityMixin {
private:
struct RegisterMe {
RegisterMe() { Factory::getFactory().registerEntityType<T>(); }
};
EntityMixin() {
static RegisterMe r;
}
};
Run Code Online (Sandbox Code Playgroud)
你会像这样使用它:
class EntityType1 : public Entity, EntityMixin<EntityType1> { ... };
class EntityType2 : public Entity, EntityMixin<EntityType2> { ... };
class EntityType3 : public Entity, EntityMixin<EntityType3> { ... };
Run Code Online (Sandbox Code Playgroud)
[更新]
您还可以创建的XEO/Merlyn理念EntityBase,重命名EntityMixin,以Entity和避免需要从两个地方继承.我实际上认为我的原始提案更清楚; 你甚至可以调用mixin FactoryMixin并将其粘贴到你想要注册的任何课程上.
但Xeo/Merlyn版本看起来像这样:
class Factory {
public:
static Factory &getFactory() { static Factory f; return f; }
template <typename EntityType>
void registerEntityType() { ... }
};
class EntityBase { ... } ;
template <typename T>
class Entity : public EntityBase {
private:
struct RegisterMe {
RegisterMe() { Factory::getFactory().registerEntityType<T>(); }
};
Entity() {
static RegisterMe r;
}
};
class EntityType1 : public Entity<EntityType1> { ... };
class EntityType2 : public Entity<EntityType2> { ... };
class EntityType3 : public Entity<EntityType3> { ... };
Run Code Online (Sandbox Code Playgroud)
任何解决方案的关键是CRTP并谨慎使用静态局部变量以避免初始化顺序问题.
如果有人仍然感兴趣,我想通了。静态模板成员变量不会自动实例化,除非使用它们。我需要在调用构造函数之前实例化它,因此我无法将其设置为静态本地。解决方案是使其成为静态模板成员变量,然后在成员函数(我使用构造函数)中使用它(如果需要,只需在其上调用空函数)。这迫使编译器为曾经声明的每个模板参数实例化静态,因为实例化的构造函数代码使用它,例如:
我的注册表类,其空白函数用于调用
template <typename DerivedType>
class Registrar
{
public:
Registrar();
void check(){}
};
Run Code Online (Sandbox Code Playgroud)
我想注册我的班级。
template <typename Product, typename DerivedType>
class AbstractFactory: public AbstractFactoryBase<Product>
{
public:
AbstractFactory();
~AbstractFactory();
private:
static Registrar<DerivedType> registrar;
};
Run Code Online (Sandbox Code Playgroud)
注册商的构造函数
template <typename DerivedType>
Registrar<DerivedType>::Registrar()
{
std::cout << DerivedType::name() << " initialisation" << std::endl;
g_AbstractFactories.registerFactoryType<DerivedType>(DerivedType::name());
}
Run Code Online (Sandbox Code Playgroud)
和我的类构造函数
template <typename Product, typename DerivedType>
AbstractFactory::AbstractFactory()
{
registrar.check();
}
Run Code Online (Sandbox Code Playgroud)