QObject универсальный обработчик сигнала

(С «обработчиком сигнала» я имею в виду слоты, а не обработчики для сигналов POSIX.)

Мне нужно & quot; подключить & quot; (probably not с помощьюQObject::connect напрямую)all signals из экземпляра (еще не известного) подкласса QObject дляone single slot другого QObject. Мне это нужно для отправки сигнала (с аргументами) по сети (для собственной системы RPC с поддержкой сигналов).

(Под "еще не известным" я имею в виду, что мой код должен быть настолько универсальным, насколько это возможно. Поэтому он не может содержатьconnect оператор для каждого сигнала в каждом классе, который я использую с моей системой RPC, но что-то вродеRPC::connectAllSignals(QObject*);, который затем сканирует все сигналы во время выполнения и соединяет их.)

То, чего я хотел бы достичь, это: обрабатывать все сигналы и сериализовать их (имя сигнала + аргументы). Я уже могу сериализовать аргументы, но я не знаю, как получить имя сигнала. После поиска в Google, кажется, невозможно использовать что-то подобное, как естьsender() для экземпляра QObject. Поэтому мне нужно сделать что-то гораздо более сложное.

Моя текущая система типов для передачи аргументов целевой функции на удаленном конце в любом случае ограничена некоторыми типами. (Это потому что мне нужноqt_metacall, который исключает аргументы типаvoid* с & quot; правильными типами & quot; позади них. Моя система RPC использует QVariants только с несколькими типами внутри, и я конвертирую их вvoid* правильных типов с использованием пользовательских методов. Я слышал оQVariant::constData слишком поздно, чтобы использовать его, и он, вероятно, все равно не подойдет; поэтому я буду придерживаться своего преобразования типов, если нет недостатка.)

Целевой интервал, в который должны быть отображены все сигналы, должен выглядеть примерно так:

void handleSignal(QByteArray signalName, QVariantList arguments);

Было бы лучше, если бы решение поддерживалось C ++ 03, поэтому я хочу использовать шаблоны с переменным числом аргументов только в том случае, еслиbig недостаток не использовать их. В этом случае C ++ 11 в порядке, поэтому я также рад ответам, использующим C ++ 11.

Теперь мойpossible solution на вопрос, о котором я думаю:

Я мог сканировать все сигналы объекта, используя егоQMetaObject а затем созданиеQSignalMapper (или что-то подобное, что передает все аргументы) дляeach сигнал. Это легко, и мне не нужна помощь с этой стороны. Как упоминалось ранее, я уже ограничен некоторыми типами аргументов, и я также могу жить с ограничением количества аргументов.

Это звучит как грязный хак, но я мог бы использовать какой-то пользовательский, основанный на шаблонах преобразователь сигналов, как этот (в этом примере для трех аргументов):

template<class T1, class T2, class T3>
class MySignalMapper : public QObject
{
    Q_OBJECT
public:
    void setSignalName(QByteArray signalName)
    {
        this->signalName = signalName;
    }
signals:
    void mapped(QByteArray signalName, QVariantList arguments);
public slots:
    void map(T1 arg1, T2 arg2, T3 arg3)
    {
        QVariantList args;
        // QVariant myTypeConverter<T>(T) already implemented:
        args << myTypeConverter(arg1);
        args << myTypeConverter(arg2);
        args << myTypeConverter(arg3);
        emit mapped(signalName, args);
    }
private:
    QByteArray signalName;
};

Тогда я мог бы подключить QMetaMethod под названиемmethod (который известен как сигнал) объекта QObject, называемогоobj как это (который может быть сгенерирован с использованием некоторого вида сценария для всех поддерживаемых типов и количества аргументов ... да ...it's getting dirty!):

    // ...
}
else if(type1 == "int" && type2 == "char" && type3 == "bool")
{
    MySignalMapper<int,char,bool> *sm = new MySignalMapper<int,char,bool>(this);
    QByteArray signalName = method.signature();
    signalName = signalName.left(signalName.indexOf('(')); // remove parameters
    sm->setMember(signalName);

    // prepend "2", like Qt's SIGNAL() macro does:
    QByteArray signalName = QByteArray("2") + method.signature();

    // connect the mapper:
    connect(obj, signalName.constData(),
            sm, SLOT(map(int,char,bool)));
    connect(sm, SIGNAL(mapped(int,char,bool)),
            this, SLOT(handleSignal(const char*,QVariantList)));
}
else if(type1 == ...)
{
    // ...

Как этоmay workЭто действительно грязное решение. Мне нужно либо много макросов, чтобы охватить все комбинации типов максимумN аргументы (гдеN примерно от 3 до 5 (пока не известно) или простой скрипт, генерирующий код для всех случаев. Проблема в том, что это будетlot случаев, когда я поддерживаю около 70 различных типов на аргумент (10 примитивных типов + вложенные списки и карты с глубиной 2 дляevery типа их). Таким образом, для ограничения количества аргументовN имеютсяN ^ 70 случаев, чтобы покрыть!

Is there a completely different approach for this objective, which I'm overlooking?

UPDATE:

Я решил проблему самостоятельно (см. Ответ). Если вы заинтересованы в полном исходном коде, посмотрите мой репозиторий на bitbucket моей системы RPC, который я только что опубликовал: bitbucket.org/leemes/qtsimplerpc

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

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