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);
나는 알고있다, 그건 추한 . 그러나이 문제를 해결할 방법이 없습니다. 오늘의 교훈은 신호와 슬롯에 과부하를주지 마십시오!
부록 : 캐스트에 대해 정말로 짜증나는 것은
- 하나는 클래스 이름을 두 번 반복합니다
- 일반적으로
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);