首页 文章

连接Qt 5中的过载信号和插槽

提问于
浏览
99

我在Qt 5中无法掌握新的信号/槽语法(使用指向成员函数的指针),如New Signal Slot Syntax中所述 . 我尝试改变这个:

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))

我在Linux上尝试过使用clang和gcc,都使用 -std=c++11 .

我做错了什么,我该如何解决?

4 回答

  • 7

    这里的问题是 two 信号具有该名称: 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);
    

    我知道,这是 ugly . 但是_____99895的教训是:不要让信号和插槽过载!


    Addendum :对演员来说真正令人讨厌的是

    • 一次重复两次 class 名称

    • 必须指定返回值,即使它通常是 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), ...)
    

    我个人认为它不是很有用 . 我希望当Creator(或你的IDE)在自动完成获取PMF的操作时自动插入正确的强制转换时,这个问题会自行消失 . 但同时......

    注意:基于PMF的连接语法 does not require C++11


    Addendum 2 :在Qt 5.7中添加了辅助函数来缓解这种情况,模仿我上面的解决方法 . 主助手是qOverload(你也有qConstOverloadqNonConstOverload) .

    用法示例(来自文档):

    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)
    
  • 0

    错误消息是:

    错误:没有用于调用QObject :: connect的匹配函数(QSpinBox *&,<unresolved overloaded function type>,QSlider *&,void(QAbstractSlider :: *)(int))

    其中重要的部分是提到“ unresolved overloaded function type ” . 编译器不知道您的意思是 QSpinBox::valueChanged(int) 还是 QSpinBox::valueChanged(QString) .

    有几种方法可以解决过载:

    为connect()提供合适的模板参数

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

    这会强制 connect()&QSpinBox::valueChanged 解析为带有 int 的重载 .

    如果slot参数有未解决的重载,那么您需要将第二个模板参数提供给 connect() . 不幸的是,'s no syntax to ask for the first to be inferred, so you'll需要供应两者 . 那是第二种方法可以帮助:

    使用正确类型的临时变量

    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);
    
  • 195

    实际上,你可以用lambda包装你的插槽,这个:

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

    看起来会更好 . :\

  • 12

    上面的解决方案有效,但是我用一种稍微不同的方式解决了这个问题,使用了一个宏,所以以下是以下情况:

    #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);
    

相关问题