По сути, я хочу автоматически зарегистрировать функции создателя объекта в фабрике объектов для набора классов, определенных во многих заголовочных файлах.
Ответ на в этом посте , приведенный выше, дает решение- но это не соответствует моим ограничениям.
Я работаю над существующей кодовой базой.Для классов, которые мне нужно зарегистрировать, уже существует макрос, следующий за объявлениями класса, который принимает класс в качестве параметра.Если бы мне удалось расширить существующее определение макроса, чтобы оно также выполняло регистрацию, это сэкономило бы много времени, поскольку не пришлось бы изменять существующий код.
Самое близкое решение, которое мне удалось найтисоздает макрос, который определяет специализацию шаблона для метода, который регистрирует этот объект, затем вызывает ранее определенный метод специализации шаблона - таким образом объединяя в цепочку все вызовы регистра.Затем, когда я хочу зарегистрировать все классы, я просто вызываю последнюю определенную специализацию, и она регистрирует все в обратном порядке появления #include.
Ниже я опубликовал простой рабочий пример, демонстрирующий мое решение.пока что.
Единственное предостережение в том, что у меня нет возможности автоматически отслеживать последний зарегистрированный тип для вызова в цепочке.Поэтому я продолжаю переопределять #define LAST_CHAIN_LINK, чтобы он был самым последним специализированным именем типа.Это означает, что мне нужно было бы добавить две строки # undef / # define после каждого существующего вызова макроса - я бы очень хотел этого избежать.
Основной вопрос: есть ли в приведенном ниже кодеМожно ли определить макрос REGISTER_CHAIN для работы без использования LAST_CHAIN_LINK # undef / # определения кода?
Если бы можно было переопределить токен LAST_CHAIN_LINK внутри метода REGISTER_CHAIN ...
Я предполагаю, что какое-то решение возможно с использованием функции препроцессора __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