Manipulador de sinal genérico QObject

(Com "manipulador de sinal" quero dizer slots, não manipuladores para sinais POSIX.)

Eu preciso "ligar" (provavelmente não usandoQObject::connect diretamente)todos os sinais de uma instância de uma subclasse (ainda não conhecida) de QObject paraum único slot de outro QObject. Eu preciso disso para enviar o sinal (com argumentos) pela rede (para um sistema RPC próprio com suporte a sinais).

(Com "ainda não conhecido", quero dizer que o meu código deve ser o mais genérico possível. Então, ele não deve conterconnect declaração para cada sinal em cada classe que estou usando com o meu sistema RPC, mas fornecer algo comoRPC::connectAllSignals(QObject*);, que então escaneia todos os sinais durante o tempo de execução e os conecta.)

O que eu gostaria de alcançar é: manipular todos os sinais e serializá-los (nome do sinal + argumentos). Eu já posso serializar os argumentos, mas não sei como obter o nome do sinal. Depois de googlar, parece ser impossível usar algo semelhante como hásender() para a instância do QObject. Então eu preciso fazer algo muito mais complicado.

Meu sistema de tipos atual para passar os argumentos para uma função de destino no final remoto é restrito a alguns tipos de qualquer maneira. (Isso é porque eu precisoqt_metacall, que excetua os argumentos para ser do tipovoid* com os "tipos corretos" por trás deles. Meu sistema RPC usa QVariants com apenas alguns tipos internamente e eu os converto paravoid* dos tipos corretos usando métodos personalizados. Eu ouvi sobreQVariant::constData tarde demais para usá-lo, e provavelmente não vai caber de qualquer maneira; então eu vou ficar com a minha conversão de tipo, se não houver desvantagem.)

O slot de destino, onde todos os sinais devem ser mapeados, deve ser semelhante a este:

void handleSignal(QByteArray signalName, QVariantList arguments);

Seria melhor se a solução fosse suportada pelo C ++ 03, então eu só quero usar modelos variadic se for umgrande desvantagem de não usá-los. Nesse caso, o C ++ 11 está OK, então também estou feliz com as respostas usando o C ++ 11.

Agora meusolução possível para a questão que estou pensando:

Eu poderia escanear todos os sinais do objeto usando seuQMetaObject e depois criar umQSignalMapper (ou algo semelhante que passa todos os argumentos) paracada sinal. Isso é fácil e não preciso de ajuda nessa parte. Como mencionei antes, já estou restrito a alguns tipos de argumentos, e também posso viver com uma restrição na contagem de argumentos.

Parece um hack sujo, mas eu poderia usar algum tipo de mapeadores de sinais personalizados baseados em modelos como este (neste exemplo para três argumentos):

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;
};

Então eu poderia conectar um QMetaMethod chamadomethod (que é conhecido por ser um sinal) de um QObject chamadoobj assim (que pode ser gerado usando algum tipo de script para todos os tipos suportados e contagens de argumentos ... sim ...está ficando sujo!):

    // ...
}
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 == ...)
{
    // ...

Como issopode funcionar, é realmente uma solução suja. Eu precisaria de um monte de macros para cobrir todas as combinações de tipos para no máximoN argumentos (ondeN é de cerca de 3 a 5, ainda não conhecido) ou um script simples que gera o código para todos os casos. O problema é que isso será ummuito de casos, como eu estou apoiando cerca de 70 tipos diferentes por argumento (10 tipos primitivos + listas aninhadas e mapas com profundidade 2 paracada tipo deles). Então, para um limite de contagem de argumentos deN háN ^ 70 casos a cobrir!

Existe uma abordagem completamente diferente para esse objetivo, que eu estou negligenciando?

ATUALIZAR:

Eu resolvi o problema sozinho (ver resposta). Se você estiver interessado no código-fonte completo, veja meu repositório no bitbucket do meu sistema RPC, que acabei de publicar: bitbucket.org/leemes/qtsimplerpc

questionAnswers(3)

yourAnswerToTheQuestion