我无法得到认真处理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))
我试着铛和gcc在Linux上,都与-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的要挑,通过它铸造到正确的类型的一种:
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), ...)
我个人觉得这不是真的有用。 我希望这个问题本身消失时,创作者(或您的IDE)自动填充服用的PMF时的操作将自动插入正确的演员。 但是在此期间...
注:基于PMF-CONNECT语法不需要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)
该错误消息是:
错误:调用没有匹配的功能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
将选择所需的过载,现在它可以成功地被取代到模板中。 这同样适用与“空位”的说法,我觉得在这种情况下那么繁琐。
使用转换
我们能够避免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);