C++ 如何在不使用QT5中的lambdas的情况下,将具有int参数的信号连接到具有enum参数的插槽?

C++ 如何在不使用QT5中的lambdas的情况下,将具有int参数的信号连接到具有enum参数的插槽?,c++,qt,lambda,signals-slots,C++,Qt,Lambda,Signals Slots,我正在尝试将QComboBox中的信号currentinexchanged(int)连接到我的类中接收枚举的插槽,如Foo::mySlot(EnumFoo) 我知道所有这些方法都不起作用: connect(cb,&QComboBox::currentIndexChanged,foo,&foo::mySlot) connect(cb、static_cast(&QComboBox::currentIndexChanged)、foo和foo::mySlot) connect(cb,&QComboBox

我正在尝试将
QComboBox
中的信号
currentinexchanged(int)
连接到我的类中接收枚举的插槽,如
Foo::mySlot(EnumFoo)

我知道所有这些方法都不起作用:

  • connect(cb,&QComboBox::currentIndexChanged,foo,&foo::mySlot)
  • connect(cb、static_cast(&QComboBox::currentIndexChanged)、foo和foo::mySlot)
  • connect(cb,&QComboBox::currentIndexChanged,foo,static_cast(&foo::mySlot))
  • 因为在C/C++中,
    int
    从不隐式强制转换为枚举类型。相反,我认为如果我的信号有一个enum参数,我可以毫无问题地将它连接到一个带有int参数的插槽

    我知道如何使用lambda函数解决这个问题:

    连接(cb,&QComboBox::currentIndexChanged,[=](inti){foo.mySlot(static_cast(i));})

    没有lambda函数,有没有办法解决这个问题

    编辑:使用我提出的解决方案,我以这种方式连接Foo::mySlot

    LambdaWrapper *lw = new LambdaWrapper;
    lw->connect(cb, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [=](int i){ foo.mySlot(static_cast<EnumFoo>(i)); }, foo);
    
    LambdaWrapper*lw=新的LambdaWrapper;
    lw->connect(cb,static_cast(&QComboBox::currentIndexChanged),[=](inti){foo.mySlot(static_cast(i));},foo);
    

    我再也不用担心断开连接的事情了。只需管理lw的寿命。

    使用一个中间插槽,该插槽接受int并直接调用另一个插槽函数

    class Foo : public QObject
    {
        Q_OBJECT:
    
    public slots:
        void IndexChanged(int intParam);    
        void mySlot(EnumFoo fooType);
    };    
    
    void Foo::IndexChanged(int index);
    {
        EnumFoo fooType = <static_cast<EnumFoo>(index);
        mySlot(fooType);
    }
    
    connect(cb, &QComboBox::currentIndexChanged, foo, &Foo::IndexChanged);
    
    class Foo:public QObject
    {
    Q_对象:
    公众时段:
    void IndexChanged(int intParam);
    void mySlot(EnumFoo fooType);
    };    
    void Foo::IndexChanged(int索引);
    {
    
    EnumFoo fooType=我创建了一个小类来自动处理这个断开连接的东西

    lambdawrapper.h

    class LambdaWrapper : public QObject {
        Q_OBJECT
    public:
        explicit LambdaWrapper(QObject* parent = 0);
        virtual ~LambdaWrapper();
    
        template<typename Func1, typename Func2>
        void connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender,
                     Func1 signal,
                     Func2 slot,
                     QObject* receiver = 0) {
            connections << QObject::connect(sender, signal, slot);
            helperConnection(receiver);
        }
    
    private slots:
        void disconnectReceiver(QObject* obj);
    
    private:
        void helperConnection(QObject* obj);
        QList<QMetaObject::Connection> connections;
        QObjectList receivers;
    };
    
    connect member的第4个参数是可选的,表示在lambda内部调用的某个QObject指针(如果在已删除此对象的情况下调用lambda,则会导致程序崩溃)。如果您传递此参数,则其已销毁的信号将连接到LambdaWrapper中的插槽,该插槽可确保在销毁此接收器时断开与此接收器的所有连接


    它相当脏,但解决了我的问题。现在我可以直接连接到lambda,不必担心断开连接。

    有很多方法可以避免lambda函数,其中有编写自己的包含枚举的类,提供一个“包装器”用
    静态_cast
    转发其参数的信号/插槽,其作用与lambda完全相同……你是否被lambda冒犯了(我肯定它不是那样的意思),您是否习惯了不太强的类型化语言,或者您是否有这样的误解,即这将破坏~performance~?不,这只是好奇。事实上,我有一点怀疑:我不太清楚在使用
    销毁QComboBox或Foo类之前,是否以及在什么情况下应该释放
    QMetaObject::Connection
    >QObject::disconnect(常量QMetaObject::Connection&)
    重载的成员。或者如果我们可以忽略它。如果我可以忽略这个断开连接的东西,使用lambdas就没有问题。另一方面,如果我必须处理它,也许我应该使用您所指出的包装器插槽。我想同样的解决方案,不幸的是,我们必须创建另一个插槽,但这可以解决问题。如果我不必管理这个人的话当使用lambda解决方案时,我没有理由不使用它们。但我仍然不太清楚何时必须手动断开与lambda的连接,何时可以忽略它们。每次调用信号时,lambda函数都将被执行,因此如果您不希望发生这种情况,您需要断开与lambda的连接所以我总是必须断开这个连接,不管lambda中调用了什么对象(并通过引用捕获)超出范围,或者,如果动态创建,其指针将被删除。如果我不这样做,我的应用程序肯定会崩溃或segfault,因为如果触发信号,lambda将被执行,但它的调用是一个不存在的对象实例。对吗?如果对象可能超出lambda的范围,编译器应该警告您。如果将lambda连接到的对象被删除,连接将自动删除。我知道,当发出连接到lambda的信号的对象被删除时,连接将被删除。但是,如果我将一个信号从一个对象连接到lambda,并捕获另一个对象的动态分配指针和cal,会发生什么从lambda中的这个对象中删除成员?如果我以某种方式删除这个对象,然后触发调用这个lambda的信号?我没有测试它,但我确信程序会崩溃。
    LambdaWrapper::LambdaWrapper(QObject *parent) : QObject(parent) { }
    
    LambdaWrapper::~LambdaWrapper() {
       for (const QMetaObject::Connection& c : connections)
           QObject::disconnect(c);
    }
    
    void LambdaWrapper::disconnectReceiver(QObject *obj) {
        if (receivers.contains(obj)) {
            QList<const QMetaObject::Connection*> toRemove;
            const int n = receivers.size();
            for (int i=0; i<n ; ++i) {
                if (receivers.at(i) == obj) {
                    disconnect(connections.at(i));
                    toRemove << & connections.at(i);
                }
            }
    
            receivers.removeAll(obj);
            for (const QMetaObject::Connection* c : toRemove)
                connections.removeAll(*c);
        }
    }
    
    void LambdaWrapper::helperConnection(QObject* receiver) {
        receivers << receiver;
        if (receiver) QObject::connect(receiver, &QObject::destroyed, this, &LambdaWrapper::disconnectReceiver);
    }
    
    foo.h
    ....
    class Foo : public QMainWindow
    ....
    private:
        LambdaWrapper* lw;
    ....
    
    foo.cpp
    .... 
    lw = new LambdaWrapper(this);
    QCheckBox *ck = new QCheckBox("check");
    lw->connect(ck, &QAbstraceButton::toggled, [=](bool b){ /* do stuff */}, 0);
    ....