c++ - 注册机制 - 使用宏自动注册对象创建者函数
c++注册机制 (2)
基本上,我想自动注册一个对象工厂的对象创建器函数为许多头文件定义的一堆类。
这篇文章的最佳答案提供了一个解决方案 - 但它不适合我的限制。
我正在研究现有的代码库。 对于需要注册的类,已经有一个类声明后面的一个宏,它将类作为参数。 如果我能够扩展现有的宏定义来进行注册,那么就可以节省很多时间,因为不需要改变现有的代码。
我能够想到的最接近的解决方案是创建一个宏定义一个方法的模板专门化,注册该对象,然后调用之前定义的模板专门化方法 - 从而链接所有的注册调用。 然后,当我想注册所有类时,我只是调用最近定义的特化,并且它以与#include外观相反的顺序注册了所有的类。
下面,我已经发布了一个简单的工作示例,显示了我的解决方案。
唯一需要注意的是,我无法自动追踪上一次注册类型的链接调用。 所以我不断重新定义#define LAST_CHAIN_LINK成为最近专门的类型名称。 这意味着我必须在每个现有的宏调用之后添加两行#undef /#define - 我真的想避免这种情况。
主要问题:在下面的代码中,是否有任何方法可以定义REGISTER_CHAIN宏而不使用LAST_CHAIN_LINK#undef /#define代码?
如果只能重新定义REGISTER_CHAIN方法中的LAST_CHAIN_LINK标记...
我的猜测是某些解决方案可能使用__COUNTER__
预处理器功能,但是在目标平台之一(OS X使用gcc 4.2.x)上不可用,因此不是一个选项。
简单的例子(在GNU C ++ 4.4.3上编译):
#include <map>
#include <string>
#include <iostream>
struct Object{ virtual ~Object() {} }; // base type for all objects
// provide a simple create function to derived classes
template<class T> struct ObjectT : public Object {
static Object* create() { return new T(); }
};
struct ObjectFactory {
// pass in creator function pointer to register it to id
static Object* create(const std::string& id, Object* (*creator)() = 0) {
static std::map<std::string, Object* (*)()> creators;
return creator && (creators[id] = creator) ? 0 : creators.find(id) != creators.end() ? (*creators.find(id)->second)() : 0;
}
template<class T = int> struct Register { static void chain() {} };
};
#define LAST_CHAIN_LINK // empty to start
#define REGISTER_CHAIN(T) \
template<> void ObjectFactory::Register<T>::chain() \
{ \
ObjectFactory::create(#T, T::create); \
std::cout << "Register<" << #T << ">::chain()\n"; \
ObjectFactory::Register<LAST_CHAIN_LINK>::chain(); \
}
struct DerivedA : public ObjectT<DerivedA> { DerivedA() { std::cout << "DerivedA constructor\n"; } };
REGISTER_CHAIN(DerivedA);
// Can these next two lines be eliminated or folded into REGISTER_CHAIN?
#undef LAST_CHAIN_LINK
#define LAST_CHAIN_LINK DerivedA
struct DerivedB : public ObjectT<DerivedB> { DerivedB() { std::cout << "DerivedB constructor\n"; } };
REGISTER_CHAIN(DerivedB);
// Can these next two lines be eliminated or folded into REGISTER_CHAIN?
#undef LAST_CHAIN_LINK
#define LAST_CHAIN_LINK DerivedB
struct DerivedC : public ObjectT<DerivedC> { DerivedC() { std::cout << "DerivedC constructor\n"; } };
REGISTER_CHAIN(DerivedC);
// Can these next two lines be eliminated or folded into REGISTER_CHAIN?
#undef LAST_CHAIN_LINK
#define LAST_CHAIN_LINK DerivedC
struct DerivedD : public ObjectT<DerivedD> { DerivedD() { std::cout << "DerivedD constructor\n"; } };
REGISTER_CHAIN(DerivedD);
// Can these next two lines be eliminated or folded into REGISTER_CHAIN?
#undef LAST_CHAIN_LINK
#define LAST_CHAIN_LINK DerivedD
int main(void)
{
// Call last link in the register chain to register all object creators
ObjectFactory::Register<LAST_CHAIN_LINK>::chain();
delete ObjectFactory::create("DerivedA");
delete ObjectFactory::create("DerivedB");
delete ObjectFactory::create("DerivedC");
delete ObjectFactory::create("DerivedD");
return 0;
}
示例输出:
> g++ example.cpp && ./a.out
Register<DerivedD>::chain()
Register<DerivedC>::chain()
Register<DerivedB>::chain()
Register<DerivedA>::chain()
DerivedA constructor
DerivedB constructor
DerivedC constructor
DerivedD constructor
使用Martin / @grundprinzip的建议,我已经能够解决我的问题。 我不得不稍微修改他的方法来允许在名称空间中注册类。
感谢Martin!
但是,我现在有一个后续问题:编译器是不是可以完全优化静态ObjectFactory :: Register :: creator变量(相当于@grundprinzip代码中的is_Registered _ ## T) - 因为没有代码实际上引用这个值?
如果是这样,那么优化出变量将优化初始化...从而打破我希望实现的。
这里是修改后的代码:
#include <map>
#include <string>
#include <iostream>
struct Object{ virtual ~Object() {} }; // base type for all objects
struct ObjectFactory {
static Object* create(const std::string& id) { // creates an object from a string
const Creators_t::const_iterator iter = static_creators().find(id);
return iter == static_creators().end() ? 0 : (*iter->second)(); // if found, execute the creator function pointer
}
private:
typedef Object* Creator_t(); // function pointer to create Object
typedef std::map<std::string, Creator_t*> Creators_t; // map from id to creator
static Creators_t& static_creators() { static Creators_t s_creators; return s_creators; } // static instance of map
template<class T = int> struct Register {
static Object* create() { return new T(); };
static Creator_t* init_creator(const std::string& id) { return static_creators()[id] = create; }
static Creator_t* creator;
};
};
#define REGISTER_TYPE(T, STR) template<> ObjectFactory::Creator_t* ObjectFactory::Register<T>::creator = ObjectFactory::Register<T>::init_creator(STR)
namespace A { struct DerivedA : public Object { DerivedA() { std::cout << "A::DerivedA constructor\n"; } }; }
REGISTER_TYPE(A::DerivedA, "A");
namespace B { struct DerivedB : public Object { DerivedB() { std::cout << "B::DerivedB constructor\n"; } }; }
REGISTER_TYPE(B::DerivedB, "Bee");
namespace C { struct DerivedC : public Object { DerivedC() { std::cout << "C::DerivedC constructor\n"; } }; }
REGISTER_TYPE(C::DerivedC, "sea");
namespace D { struct DerivedD : public Object { DerivedD() { std::cout << "D::DerivedD constructor\n"; } }; }
REGISTER_TYPE(D::DerivedD, "DEE");
int main(void)
{
delete ObjectFactory::create("A");
delete ObjectFactory::create("Bee");
delete ObjectFactory::create("sea");
delete ObjectFactory::create("DEE");
return 0;
}
产生正确的结果:
> g++ example2.cpp && ./a.out
A::DerivedA constructor
B::DerivedB constructor
C::DerivedC constructor
D::DerivedD constructor
我发现你的概念很复杂,我不确定是否需要。 从我的角度来看,当添加下面的代码时,你的问题可以被绕开:
#include <iostream>
#include <map>
#include <string>
struct Object{}; // Value Object
// provide a simple create function to derived classes
template<class T> struct ObjectT : public Object {
static Object* create() { return new T(); }
};
struct ObjectFactory {
std::map<std::string, Object* (*)()> creators_factory;
static ObjectFactory* instance()
{
static ObjectFactory* __self = NULL;
if (__self == NULL)
__self = new ObjectFactory();
return __self;
}
template <class T> bool reg(const std::string& id, Object* (*creator)() )
{
creators_factory[id] = creator;
return true;
}
// pass in creator function pointer to register it to id
static Object* create(const std::string& id) {
return instance()->creators_factory[id]();
}
};
#define REGISTER_CHAIN(T) bool isRegistered_##T = ObjectFactory::instance()->reg<T>(#T, T::create)
struct DerivedA : public ObjectT<DerivedA> { DerivedA() { std::cout << "DerivedA constructor\n"; } };
REGISTER_CHAIN(DerivedA);
struct DerivedB : public ObjectT<DerivedB> { DerivedB() { std::cout << "DerivedB constructor\n"; } };
REGISTER_CHAIN(DerivedB);
struct DerivedC : public ObjectT<DerivedC> { DerivedC() { std::cout << "DerivedC constructor\n"; } };
REGISTER_CHAIN(DerivedC);
struct DerivedD : public ObjectT<DerivedD> { DerivedD() { std::cout << "DerivedD constructor\n"; } };
REGISTER_CHAIN(DerivedD);
int main(void)
{
// Call last link in the register chain to register all object creators
//ObjectFactory::Register<LAST_CHAIN_LINK>::chain();
delete ObjectFactory::create("DerivedA");
delete ObjectFactory::create("DerivedB");
delete ObjectFactory::create("DerivedC");
delete ObjectFactory::create("DerivedD");
return 0;
}
我希望这有帮助。
最好的问候,马丁