Фабричен шаблон в C++: автоматично генериране на изричен createInstance()-метод

Имам проблем с писането на рамка на C++, че потребителите трябва да имат по-малко режийни разходи, отколкото е възможно, за да я използват. Потребителите могат да публикуват работата си в рамките, като създадат споделена библиотека, която съдържа клас, който се извлича от 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 и подходящо манипулиране на имената. (Знам всяко пространство от имена + име на клас от конфигурационен файл) Но не мисля, че това е правилно решение, особено извикването на конструктор не е същото като обикновено извикване на функция... но е много интересно...


person Dudero    schedule 05.07.2011    source източник


Отговори (2)


Не мога да си представя начин да създам това автоматично без никакво кодиране за част от потребителя. Мога да си представя начини да го опростя, може би с помощта на макрос:

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

И потребителят просто трябва да постави своя cpp файл:

OBJECT_CREATOR(UserClass);
person bcsanches    schedule 05.07.2011
comment
Благодаря, един ред е по-добър от четири ;) - person Dudero; 07.07.2011

Предполагам, че извикването на потребителската функция чрез 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);

Този дизайн отговаря ли на вашите нужди?

person n. 1.8e9-where's-my-share m.    schedule 05.07.2011
comment
Идеята ти звучи много интересно, но при мен не работи. Конструкторът на статичния помощен клас не е постигнат... Трябва ли това да се случи чрез dlopen-извикване на споделената библиотека на потребителите или има повече предварителни условия? - person Dudero; 07.07.2011
comment
О-о, ужасно съжалявам, това наистина не работи. Ще ви уведомя, ако мога да го поправя. - person n. 1.8e9-where's-my-share m.; 07.07.2011