我在Qt 5中无法掌握新的信号/槽语法(使用指向成员函数的指针),如新信号槽语法中所述.我尝试改变这个:
QObject::connect(spinBox, SIGNAL(valueChanged(int)),
slider, SLOT(setValue(int));
Run Code Online (Sandbox Code Playgroud)
对此:
QObject::connect(spinBox, &QSpinBox::valueChanged,
slider, &QSlider::setValue);
Run Code Online (Sandbox Code Playgroud)
但是当我尝试编译它时出错:
错误:没有匹配的函数用于调用
QObject::connect(QSpinBox*&, <unresolved overloaded function type>, QSlider*&, void (QAbstractSlider::*)(int))
我曾经尝试过在Linux上使用clang和gcc -std=c++11.
我做错了什么,我该如何解决?
pep*_*ppe 220
这里的问题是有两个信号具有该名称:QSpinBox::valueChanged(int)和QSpinBox::valueChanged(QString).从Qt 5.7开始,提供了辅助函数来选择所需的过载,因此您可以编写
connect(spinbox, qOverload<int>(&QSpinBox::valueChanged),
slider, &QSlider::setValue);
Run Code Online (Sandbox Code Playgroud)
对于Qt 5.6及更早版本,您需要通过将Qt转换为正确的类型来告诉Qt您要选择哪一个:
connect(spinbox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
slider, &QSlider::setValue);
Run Code Online (Sandbox Code Playgroud)
我知道,这很难看.但是没有办法解决这个问题.今天的教训是:不要使信号和插槽过载!
附录:对演员来说真正令人讨厌的是
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;
}
};
Run Code Online (Sandbox Code Playgroud)
用法:
connect(spinbox, SELECT<int>::OVERLOAD_OF(&QSpinBox::valueChanged), ...)
Run Code Online (Sandbox Code Playgroud)
我个人认为它不是很有用.我希望当Creator(或你的IDE)在自动完成获取PMF的操作时自动插入正确的强制转换时,这个问题会自行消失.但同时......
注意:基于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)
Run Code Online (Sandbox Code Playgroud)
Tob*_*ght 12
错误消息是:
错误:没有匹配的函数用于调用
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);
Run Code Online (Sandbox Code Playgroud)
这迫使connect()解决&QSpinBox::valueChanged进入过载的问题int.
如果你对slot参数有未解决的重载,那么你需要提供第二个模板参数connect().不幸的是,没有语法要求推断第一个,所以你需要提供两者.那是第二种方法可以帮助:
void(QSpinBox::*signal)(int) = &QSpinBox::valueChanged;
QObject::connect(spinBox, signal,
slider, &QSlider::setValue);
Run Code Online (Sandbox Code Playgroud)
赋值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; }
Run Code Online (Sandbox Code Playgroud)
这允许我们写
QObject::connect(spinBox, coerce<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged),
slider, &QSlider::setValue);
Run Code Online (Sandbox Code Playgroud)实际上,你可以用lambda包装你的插槽,这个:
connect(spinbox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
slider, &QSlider::setValue);
Run Code Online (Sandbox Code Playgroud)
看起来会更好.:\