Фабричный шаблон в C++: генерация явного createInstance()- Метод автоматически

У меня есть проблема в написании C++ Framework, что пользователи должны иметь меньше накладных расходов, чем это возможно использовать. Пользователи могут публиковать свои работы в каркасах, создав общую библиотеку, которая содержит класс, производный от BaseClass платформ, и реализовав внешний метод "C" createInstance() для возврата экземпляру его производного класса. Таким образом, фреймворк может получить доступ к пользовательскому классу, вызвав метод createInstance через общую библиотеку с помощью dlsym().

class BaseClass{}
class UserClass : public BaseClass{}

extern "C"{  
   BaseClass* UserXcreateInstance(){
    return new UserClass();
   }                        
}

В рамках:

typedef BaseClass* (*CreateInstance) ();
void* handle;
CreateInstance createInstance;
handle = dlopen( "libUserLibrary.so", RTLD_LAZY | RTLD_GLOBAL );
createInstance = reinterpret_cast <CreateInstance*> dlsym( handle, "UserXcreateInstance" );
BaseClass* userX = createInstance();

Мой вопрос: возможно ли сгенерировать метод UserXcreateInstance(), который является избыточным в каждой пользовательской библиотеке, чтобы пользователю не приходилось об этом думать?

Я думал, что это будет возможно с шаблонами + макросами, но я еще не нашел способ сделать это...

Я подумал, что другой подход заключается в том, чтобы напрямую вызывать конструктор любого пользовательского класса через dlsym и подбирать названия. (Я знаю любое пространство имен + имя класса из файла конфигурации) Но я не думаю, что это правильное решение, особенно вызов конструктора - это не то же самое, что обычный вызов функции... но очень интересно...

2 ответа

Решение

Я не могу представить способ создать это автоматически без какого-либо кодирования для каждой части пользователя. Я могу представить способы упростить это, возможно, используя макрос:

#define OBJECT_CREATOR(X) \
    extern "C" {          \
         BaseClass *UserXCreateInstance() {\
             return new X(); \
         }\
    }

А пользователю просто нужно поставить на свой файл cpp:

OBJECT_CREATOR(UserClass);

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

То, что вы хотите, легко достичь с помощью CRTP. Затем конструктор статического вспомогательного объекта регистрирует соответствующие данные в центральном хранилище. Это должно идти так:

template <typename UserClass>
class BaseClass
{
  private:
    class UserObjectFactory
    {
      UserObjectFactory()
      {
        std::string myname = typeid(UserClass).name();
        CentralObjectFactory::instance()->register(this, myname);
      }
      BaseClass* XUserCreateInstance()
      {
        return new UserClass;
      }            
    };
    static UserObjectFactory factory; 
};

Пользовательский код прост:

class MyClass : public BaseClass<MyClass>
{
  // whatever
};

Предположительно, CentralObjectFactory Экземпляр содержит какую-то (мульти) карту из std::string в UserObjectFactory,

myname может быть инициализирован к некоторой уникально сгенерированной строке вместо typeid(UserClass).name(), чтобы избежать столкновений.

Если все, что вам нужно, это один объект класса каждого пользователя, вы можете сделать UserObjectFactory создать экземпляр UserClass и зарегистрируйте это вместо этого.

   std::string myname = typeid(UserClass).name();
   CentralObjectRepository::instance()->register(XUserCreateInstance(), myname);

Соответствует ли этот дизайн вашим потребностям?

Другие вопросы по тегам