Conectando sinais e slots sobrecarregados no Qt 5

Estou tendo problemas para entender a nova syntax de sinal / slot (usando o ponteiro para a function de membro) no Qt 5, conforme descrito em Nova Sintaxe do Slot de Sinal . Eu tentei mudar isso:

QObject::connect(spinBox, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int)); 

para isso:

 QObject::connect(spinBox, &QSpinBox::valueChanged, slider, &QSlider::setValue); 

mas recebo um erro quando tento compilá-lo:

erro: nenhuma function correspondente para chamada para QObject::connect(QSpinBox*&, , QSlider*&, void (QAbstractSlider::*)(int))

Eu tentei com clang e gcc no Linux, ambos com -std=c++11 .

O que estou fazendo de errado e como posso consertar isso?

   

    O problema aqui é que existem dois sinais com esse nome: QSpinBox::valueChanged(int) e QSpinBox::valueChanged(QString) . Do Qt 5.7, existem funções auxiliares fornecidas para selecionar a sobrecarga desejada, para que você possa escrever

     connect(spinbox, qOverload(&QSpinBox::valueChanged), slider, &QSlider::setValue); 

    Para o Qt 5.6 e anterior, você precisa dizer ao Qt qual você quer escolher, colocando-o no tipo correto:

     connect(spinbox, static_cast(&QSpinBox::valueChanged), slider, &QSlider::setValue); 

    Eu sei, é feio . Mas não há maneira de contornar isso. A lição de hoje é: não sobrecarregue seus sinais e slots!


    Adendo : o que realmente incomoda o casting é que

    1. se repete o nome da class duas vezes
    2. é preciso especificar o valor de retorno mesmo que seja geralmente void (para sinais).

    Então eu me encontrei às vezes usando este trecho de C ++ 11:

     template struct SELECT { template static constexpr auto OVERLOAD_OF( R (C::*pmf)(Args...) ) -> decltype(pmf) { return pmf; } }; 

    Uso:

     connect(spinbox, SELECT::OVERLOAD_OF(&QSpinBox::valueChanged), ...) 

    Eu pessoalmente acho que não é realmente útil. Espero que esse problema desapareça quando o Creator (ou seu IDE) inserir automaticamente a conversão correta ao preencher automaticamente a operação de obter o PMF. Mas enquanto isso …

    Nota: a syntax de conexão baseada em PMF não requer o C ++ 11 !


    Adendo 2 : no Qt 5.7 funções auxiliares foram adicionadas para atenuar isso, modeladas após a minha solução alternativa acima. O principal ajudante é o qOverload (você também tem qConstOverload e qNonConstOverload ).

    Exemplo de uso (dos documentos):

     struct Foo { void overloadedFunction(); void overloadedFunction(int, QString); }; // requires C++14 qOverload<>(&Foo:overloadedFunction) qOverload(&Foo:overloadedFunction) // same, with C++11 QOverload<>::of(&Foo:overloadedFunction) QOverload::of(&Foo:overloadedFunction) 

    A mensagem de erro é:

    erro: nenhuma function correspondente para chamada para QObject::connect(QSpinBox*&, , QSlider*&, void (QAbstractSlider::*)(int))

    A parte importante disso é a menção de ” tipo de function sobrecarregada não resolvida “. O compilador não sabe se você quer dizer QSpinBox::valueChanged(int) ou QSpinBox::valueChanged(QString) .

    Existem algumas maneiras de resolver a sobrecarga:

    • Forneça um parâmetro de modelo adequado para connect()

       QObject::connect(spinBox, &QSpinBox::valueChanged, slider, &QSlider::setValue); 

      Isso força o &QSpinBox::valueChanged connect() a resolver o &QSpinBox::valueChanged na sobrecarga que leva um int .

      Se você tiver sobrecargas não resolvidas para o argumento de slot, será necessário fornecer o segundo argumento de modelo para connect() . Infelizmente, não há syntax para pedir que o primeiro seja inferido, então você precisará fornecer os dois. É quando a segunda abordagem pode ajudar:

    • Use uma variável temporária do tipo correto

       void(QSpinBox::*signal)(int) = &QSpinBox::valueChanged; QObject::connect(spinBox, signal, slider, &QSlider::setValue); 

      A atribuição do signal selecionará a sobrecarga desejada e, agora, ela poderá ser substituída com sucesso no modelo. Isso funciona igualmente bem com o argumento ‘slot’, e acho que é menos complicado nesse caso.

    • Use uma conversão

      Podemos evitar o static_cast aqui, pois é simplesmente uma coerção em vez de remover as proteções do idioma. Eu uso algo como:

       // Also useful for making the second and // third arguments of ?: operator agree. template T&& coerce(U&& u) { return u; } 

      Isso nos permite escrever

       QObject::connect(spinBox, coerce(&QSpinBox::valueChanged), slider, &QSlider::setValue); 

    Na verdade, você pode apenas quebrar seu slot com lambda e isso:

     connect(spinbox, static_cast(&QSpinBox::valueChanged), slider, &QSlider::setValue); 

    vai ficar melhor. : \

    As soluções acima funcionam, mas eu resolvi isso de uma maneira um pouco diferente, usando uma macro, Então, apenas no caso, aqui está:

     #define CONNECTCAST(OBJECT,TYPE,FUNC) static_cast(&OBJECT::FUNC) 

    Adicione isso no seu código.

    Então, seu exemplo:

     QObject::connect(spinBox, &QSpinBox::valueChanged, slider, &QSlider::setValue); 

    Torna-se:

     QObject::connect(spinBox, CONNECTCAST(QSpinBox, double, valueChanged), slider, &QSlider::setValue);