@grundprinzip В моем реальном коде это не вариант, так как некоторые из типов, которые я регистрирую, являются 3dparty кодом, который я не могу изменить. К счастью, мое решение, приведенное выше, похоже, работает во всех случаях без оптимизации кода даже в сборках релизов на платформах, которые меня интересуют.

ти, я хочу автоматически зарегистрировать функции создателя объекта в фабрике объектов для набора классов, определенных во многих заголовочных файлах.

Главный ответ наэта почта, предоставляет решение - но оно не соответствует моим ограничениям.

Я работаю над существующей кодовой базой. Для классов, которые мне нужно зарегистрировать, уже существует макрос, следующий за объявлениями класса, который принимает класс в качестве параметра. Если бы я смог расширить существующее определение макроса, чтобы он также выполнял регистрацию, это сэкономило бы много времени, потому что никакой существующий код не пришлось бы изменять.

Самое близкое решение, которое мне удалось найти, - это создание макроса, который определяет специализацию шаблона для метода, который регистрирует этот объект, а затем вызывает ранее определенный метод специализации шаблона - таким образом объединяя в цепочку все вызовы регистра. Затем, когда я хочу зарегистрировать все классы, я просто вызываю последнюю определенную специализацию, и она регистрирует все в обратном порядке появления #include.

Ниже я опубликовал простой рабочий пример, который пока показывает мое решение.

Единственное предостережение в том, что я не могу автоматически отслеживать последний зарегистрированный тип для вызова в цепочке. Поэтому я продолжаю переопределять #define LAST_CHAIN_LINK, чтобы он был самым последним специализированным именем типа. Это означает, что я должен добавить две строки # undef / # define после каждого существующего вызова макроса - я бы очень хотел этого избежать.

Главный вопрос: есть ли в приведенном ниже коде способ определения макроса REGISTER_CHAIN ​​для работы без использования кода LAST_CHAIN_LINK # undef / # define?

Если бы только было возможно переопределить токен 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

Ответы на вопрос(2)

Ваш ответ на вопрос