objetos español creator c++ qt qt5

c++ - español - Conexión de señales y ranuras sobrecargadas en Qt 5



qt creator español (4)

Tengo problemas para familiarizarme con la nueva sintaxis de señal / ranura (usando el puntero a la función de miembro) en Qt 5, como se describe en Nueva sintaxis de la ranura de señal . Intenté cambiar esto:

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

a esto:

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

pero obtengo un error cuando intento compilarlo:

error: no hay función de coincidencia para llamar a QObject::connect(QSpinBox*&, <unresolved overloaded function type>, QSlider*&, void (QAbstractSlider::*)(int))

Lo he intentado con clang y gcc en Linux, ambos con -std=c++11 .

¿Qué estoy haciendo mal y cómo puedo solucionarlo?


El mensaje de error es:

error: no hay función de coincidencia para llamar a QObject::connect(QSpinBox*&, <unresolved overloaded function type>, QSlider*&, void (QAbstractSlider::*)(int))

La parte importante de esto es la mención de " tipo de función sobrecargada no resuelta ". El compilador no sabe si se QSpinBox::valueChanged(int) o QSpinBox::valueChanged(QString) .

Hay varias maneras de resolver la sobrecarga:

  • Proporcione un parámetro de plantilla adecuado para connect()

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

    Esto obliga a connect() a resolver &QSpinBox::valueChanged en la sobrecarga que toma un int .

    Si tiene sobrecargas no resueltas para el argumento de ranura, necesitará suministrar el segundo argumento de plantilla para connect() . Desafortunadamente, no hay sintaxis para pedir que se infiera la primera, por lo que deberá proporcionar ambas. Ahí es cuando el segundo enfoque puede ayudar:

  • Use una variable temporal del tipo correcto

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

    La asignación a la signal seleccionará la sobrecarga deseada, y ahora se puede sustituir con éxito en la plantilla. Esto funciona igual de bien con el argumento ''intervalo'', y me parece menos engorroso en ese caso.

  • Usa una conversión

    Podemos evitar static_cast aquí, ya que es simplemente una coacción en lugar de eliminar las protecciones del idioma. Yo uso algo como:

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

    Esto nos permite escribir

    QObject::connect(spinBox, coerce<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), slider, &QSlider::setValue);


El problema aquí es que hay dos señales con ese nombre: QSpinBox::valueChanged(int) y QSpinBox::valueChanged(QString) . Desde Qt 5.7, hay funciones de ayuda provistas para seleccionar la sobrecarga deseada, para que pueda escribir

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

Para Qt 5.6 y anteriores, debe indicarle a Qt cuál quiere elegir, seleccionándolo al tipo correcto:

connect(spinbox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), slider, &QSlider::setValue);

Lo sé, es feo . Pero no hay forma de evitar esto. La lección de hoy es: ¡no sobrecargue sus señales y ranuras!

Adición : lo que es realmente molesto sobre el reparto es que

  1. uno repite el nombre de clase dos veces
  2. uno tiene que especificar el valor de retorno incluso si generalmente es void (para señales).

Así que me he encontrado a veces usando este fragmento de C ++ 11:

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

Uso:

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

Personalmente, creo que no es realmente útil. Espero que este problema desaparezca solo cuando el Creador (o su IDE) inserte automáticamente el modelo correcto al completar automáticamente la operación de tomar el PMF. Pero mientras tanto ...

Nota: ¡la sintaxis de conexión basada en PMF no requiere C ++ 11 !

Anexo 2 : en Qt 5.7 se agregaron funciones auxiliares para mitigar esto, modelado después de mi solución anterior. El asistente principal es qOverload (también tienes qConstOverload y qNonConstOverload ).

Ejemplo de uso (de los documentos):

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


En realidad, puedes envolver tu tragamonedas con lambda y esto:

connect(spinbox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), slider, &QSlider::setValue);

se verá mejor. : /


Las soluciones anteriores funcionan, pero resolví esto de una manera ligeramente diferente, usando una macro, entonces por si acaso aquí está:

#define CONNECTCAST(OBJECT,TYPE,FUNC) static_cast<void(OBJECT::*)(TYPE)>(&OBJECT::FUNC)

Agregue esto en su código.

Entonces, tu ejemplo:

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

Se convierte en:

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