태그 보관물: qt

qt

Qt 5에서 과부하 신호 및 슬롯 연결 사용)을 파악하는 데 문제가

New Signal Slot Syntax에 설명 된 것처럼 Qt 5에서 새로운 신호 / 슬롯 구문 (멤버 함수에 대한 포인터 사용)을 파악하는 데 문제가 있습니다. 나는 이것을 바꾸려고 노력했다.

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

이에:

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

그러나 컴파일하려고하면 오류가 발생합니다.

오류 : 호출에 대한 일치 기능이 없습니다. QObject::connect(QSpinBox*&,
<unresolved overloaded function type>, QSlider*&, void
(QAbstractSlider::*)(int))

나는 리눅스에서 clang과 gcc를 사용해 보았습니다 -std=c++11.

내가 뭘 잘못하고 있으며 어떻게 해결할 수 있습니까?



답변

문제는 여기에 있다는 것입니다 : 그 이름을 가진 신호가 QSpinBox::valueChanged(int)QSpinBox::valueChanged(QString). Qt 5.7부터 원하는 과부하를 선택하기 위해 제공되는 도우미 기능이 있으므로 작성할 수 있습니다

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

Qt 5.6 이하의 경우 Qt에게 올바른 유형으로 캐스팅하여 선택하려는 Qt를 알려야합니다.

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

나는 알고있다, 그건 추한 . 그러나이 문제를 해결할 방법이 없습니다. 오늘의 교훈은 신호와 슬롯에 과부하를주지 마십시오!


부록 : 캐스트에 대해 정말로 짜증나는 것은

  1. 하나는 클래스 이름을 두 번 반복합니다
  2. 일반적으로 void(신호 의 경우) 반환 값을 지정해야합니다 .

그래서 나는 때때로이 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;
    }
};

용법:

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

나는 개인적으로 그것이 실제로 유용하지 않다는 것을 알았습니다. PMF를 수행하는 작업을 자동 완성 할 때 Creator (또는 IDE)가 올바른 캐스트를 자동으로 삽입하면이 문제가 저절로 사라질 것으로 기대합니다. 그러나 그 동안에 …

참고 : PMF 기반 연결 구문 에는 C ++ 11이 필요하지 않습니다 !


부록 2 : Qt 5.7의 도우미 기능이 위의 해결 방법을 모델로하여이를 완화하기 위해 추가되었습니다. 주요 도우미는 qOverload(당신이 또한있어 qConstOverload하고 qNonConstOverload).

사용 예 (문서에서) :

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)

부록 3 : 과부하 신호의 문서를 보면 과부하 문제에 대한 해결책이 문서 자체에 명확하게 나와 있습니다. 예를 들어 https://doc.qt.io/qt-5/qspinbox.html#valueChanged-1

참고 :이 클래스에서는 Signal valueChanged가 오버로드됩니다. 함수 포인터 구문을 사용하여이 신호에 연결하기 위해 Qt는 다음 예제와 같이 함수 포인터를 얻는 편리한 도우미를 제공합니다.

   connect(spinBox, QOverload<const QString &>::of(&QSpinBox::valueChanged),
[=](const QString &text){ /* ... */ });

답변

오류 메시지는 다음과 같습니다.

오류 : 호출에 대한 일치 기능이 없습니다. QObject::connect(QSpinBox*&, <unresolved overloaded function type>, QSlider*&, void (QAbstractSlider::*)(int))

이것의 중요한 부분은 ” 해결되지 않은 오버로드 된 함수 유형 “에 대한 언급입니다 . 당신이 무슨 뜻인지 컴파일러는 알 수 없습니다 QSpinBox::valueChanged(int)QSpinBox::valueChanged(QString).

과부하를 해결하는 몇 가지 방법이 있습니다.

  • 적합한 템플릿 매개 변수를 제공하십시오. connect()

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

    이로 인해 과부하가 걸리는 부분이 connect()해결 &QSpinBox::valueChanged됩니다 int.

    슬롯 인수에 대해 해결되지 않은 오버로드가있는 경우에 두 번째 템플릿 인수를 제공해야합니다 connect(). 불행히도, 첫 번째 추론을 요구하는 구문은 없으므로 두 가지를 모두 제공해야합니다. 그때 두 번째 접근 방식이 도움이 될 수 있습니다.

  • 올바른 유형의 임시 변수를 사용하십시오.

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

    할당 signal은 원하는 과부하를 선택하고 이제 템플릿으로 대체 할 수 있습니다. 이것은 ‘slot’인수와 똑같이 잘 작동하며,이 경우 덜 성가신 것으로 나타났습니다.

  • 전환 사용

    우리는 static_cast언어 보호를 제거하는 것이 아니라 단순히 강제이기 때문에 여기서 피할 수 있습니다 . 나는 다음과 같은 것을 사용한다 :

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

    이것은 우리가 쓸 수 있습니다

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

답변

실제로 슬롯을 람다로 감쌀 수 있습니다.

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

더 좋아 보일 것입니다. : \


답변

위의 솔루션은 작동하지만 매크로를 사용하여 약간 다른 방식으로 해결했습니다.

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

이것을 코드에 추가하십시오.

그런 다음 귀하의 예 :

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

된다 :

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


답변