Передо мной встала задача сделать некие манипуляции с конкретным классом (классами) до создания первого объекта.
Рассмотрим частный случай необходимости статической инициализации классов.
Как известно, в Qt для того, чтобы можно было передавать пользовательские типы между сигнал-слотами при Qt::QueuedConnection, необходимо предварительно зарегистрировать данный тип в мета-объектной системе Qt с помощью qRegisterMetaType<Foo>(«Foo»).
В одном из проектов есть базовый класс BaseEvent и несколько десятков наследуемых (например, EventFoo, EventBar). Мне нужно сделать регистрацию типа до вызова любого из сигналов, которые передают объекты данных классов между потоками.
Почему не регистрировать тип непосредственно перед созданием connect или в конструкторе класса, который создает connect'ы? Потому что типов много, как я написал выше, несколько десятков. Если забыть зарегистрировать тип, то об этом я узнаю только в процессе работы, так как наличие зарегистрированного типа проверяется в runtime.
Найденные решения:
1. Регистрировать в конструкторе [плохо]
class BaseEvent
{
public:
explicit BaseEvent() { qRegisterMetaType<BaseEvent>("BaseEvent"); }
}
class EventFoo : public BaseEvent
{
public:
explicit EventFoo() { qRegisterMetaType<EventFoo>("EventFoo"); }
}
class EventBar : public BaseEvent
{
public:
explicit EventBar() { qRegisterMetaType<EventBar>("EventBar"); }
}
class
2. Статический member с конструктором-инициализатором
class BaseEvent
{
public:
explicit BaseEvent() {}
private:
class Initializer
{
public:
explicit Initializer() { qRegisterMetaType<BaseEvent>("BaseEvent"); }
} static const _init;
}
class EventFoo : public BaseEvent
{
public:
explicit EventFoo() { }
private:
class Initializer
{
public:
explicit Initializer() { qRegisterMetaType<EventFoo>("EventFoo"); }
} static const _init;
}
class EventBar : public BaseEvent
{
public:
explicit EventBar() { }
private:
class Initializer
{
public:
explicit Initializer() { qRegisterMetaType<EventBar>("EventBar"); }
} static const _init;
}
Преимущества: минимальные накладные расходы по памяти (один int на весь класс), отсутствие накладных расходов при создании объекта
Недостатки: много дублирующего кода, так и хочется как-то заменить на шаблоны и/или макросы.
Что посоветуете?
Меня устраивает второй вариант, но хотелось бы избавится от тонны копипасты. Можно как-то сделать подобное на шаблонах? В идеале хотелось бы видеть что-то такое на шаблонах:
class EventFoo : public BaseEvent
{
public:
explicit EventFoo() { }
private:
static const Initializer<EventFoo> _init;
}
Или хотя бы на макросах:
class EventFoo : public BaseEvent
{
public:
explicit EventFoo() { }
private:
EVENT_INIT(EventFoo)
}