Pour des raisons de conception, j'ai besoin de trouver un moyen d'appeler QObject::connect() où les pointeurs de fonction sont passés en tant que valeurs renvoyées des appels de fonction. À savoir, au lieu d'utiliser la syntaxe vanille connect(sender, &Sender::valueChanged, receiver, &Receiver::updateValue);, je dois faire quelque chose comme ce qui suit:

//in main.cpp
SENDER *sender = new SENDER;
RECEIVER *receiver = new RECEIVER;
connect(sender, sender->get_func(), receiver, receiver->get_func() );

Où SENDER et RECEIVER sont définis comme suit:

#include <QObject>

class SENDER : public QObject {

  Q_OBJECT
  public:
    void(* get_func() ) (double, double);

  signals:
    void send_data(double x, double y);

};


void (* SENDER::get_func() )(double, double)
{
    return send_data;
}


class RECEIVER : public QObject {

  Q_OBJECT
  public:
    void receive_data(double x, double y);
    void(* get_func() ) (double, double);

};

void (* RECEIVER::get_func() )(double, double)
{
    return receive_data;
}


int main()
{
    SENDER *sender = new SENDER;
    RECEIVER *receiver = new RECEIVER;
    QObject::connect(sender, sender->get_func(), receiver, receiver->get_func() );
}

Les tentatives de compilation me donnent l'erreur suivante:

/home/abc/work/mainwindow.cpp:41: error: no matching function for call to ‘MainWindow::connect(SENDER*&, void (*)(double, double), RECEIVER*&, void (*)(double, double))’
     connect(sender, sender->get_func(), receiver, receiver->get_func() );

Qu'est-ce que je fais mal ici?

4
megamonium 20 nov. 2018 à 12:03

4 réponses

Meilleure réponse

Vos fonctions ne renvoient pas de pointeurs de fonction membre. Voici comment SENDER doit être écrit:

class SENDER : public QObject {

  Q_OBJECT
  public:
    void (SENDER::*get_func())(double, double);

  signals:
    void send_data(double x, double y);

};


void (SENDER::*SENDER::get_func())(double, double)
{
    return &SENDER::send_data;
}

get_func() doit être déclaré comme renvoyant un pointeur vers la fonction membre prenant (double, double) et renvoyant void. Et l'implémentation doit qualifier le nom du membre renvoyé et utiliser l'opérateur d'adresse de &.

Des modifications similaires doivent être apportées à RECEIVER:

class RECEIVER : public QObject {

  Q_OBJECT
  public:
    void receive_data(double x, double y);
    void (RECEIVER::*get_func())(double, double);
};

void (RECEIVER::*RECEIVER::get_func())(double, double)
{
    return &RECEIVER::receive_data;
}
2
Toby Speight 20 nov. 2018 à 09:34

Vos get_func ne renvoient pas de fonctions pointeur vers membre, ce que connect attend. Ils renvoient des pointeurs vers des fonctions.

Les corps de ceux-ci vont également échouer à se compiler, car vous renvoyez une fonction membre (avec une syntaxe incorrecte).

Vous devriez plutôt les déclarer comme

//sender.h
#include <QWidget>

class SENDER : public QWidget{

  Q_OBJECT
  public:
    void (SENDER::*get_func)(double, double)();

  signals:
    void send_data(double x, double y);

};

//sig_sender.cpp
#include "sender.h"

void (SENDER::*)(double, double) SENDER::get_func()
{
    return &SENDER::send_data;
}

//sig_receiver.h
#include <QWidget>

class RECEIVER : public QWidget{

  Q_OBJECT
  public:
    void receive_data(double x, double y);
    void (RECEIVER::*get_func)(double, double)();

};

//sig_receiver.cpp
#include "receiver.h"

void (RECEIVER::*)(double, double) RECEIVER::get_func()
{
    return &RECEIVER::receive_data;
}
2
Caleth 20 nov. 2018 à 09:22

Vous pouvez utiliser using ou typedef pour définir le type d'un pointeur vers une fonction membre:

class SENDER : public QWidget{
  Q_OBJECT
  public:
    typedef void (SENDER::*PtrFunc)(double,double); // PtrFunc pointer to member function
    PtrFunc get_func () { return &SENDER::send_data; }
  signals:
    void send_data(double x, double y) {}
};


class RECEIVER : public QWidget{
  Q_OBJECT
  public:
    using PtrFunc = void (RECEIVER::*)(double,double);
    void receive_data(double x, double y) {}
    PtrFunc get_func() { return &RECEIVER::receive_data; }
};

SENDER* sender;
RECEIVER* receiver;
//..
QObject::connect (sender, sender->get_func(), receiver, receiver->get_func());

En utilisant typedef, il est facile de le mettre comme type de résultat.

1
rafix07 20 nov. 2018 à 09:23

Une solution possible est d'utiliser auto pour déduire le type (C ++ 14) et renvoyer &Class::method:

#include <QCoreApplication>
#include <QTimer>
#include <QDebug>

class SENDER : public QObject{
    Q_OBJECT
public:
    auto get_func(){
        return &SENDER::send_data;
    }
signals:
    void send_data(double x, double y);
};

class RECEIVER : public QObject
{
    Q_OBJECT
public:
    void receive_data(double x, double y){
        qDebug()<< __PRETTY_FUNCTION__ << x <<y;
        QCoreApplication::quit();
    }
    auto get_func(){
        return &RECEIVER::receive_data;
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    SENDER *sender = new SENDER;
    RECEIVER *receiver = new RECEIVER;
    QObject::connect(sender, sender->get_func(), receiver, receiver->get_func());
    QTimer::singleShot(1000, sender, [sender](){
        emit sender->send_data(1.0, 2.0);
    });
    return a.exec();
}

#include "main.moc"

Ou:

class SENDER : public QObject{
    Q_OBJECT
public:
    void (SENDER::*get_func())(double, double){
        return &SENDER::send_data;
    }
signals:
    void send_data(double x, double y);
};

class RECEIVER : public QObject
{
    Q_OBJECT
public:
    void receive_data(double x, double y){
        qDebug()<< __PRETTY_FUNCTION__ << x <<y;
        QCoreApplication::quit();
    }
    void (RECEIVER::*get_func())(double, double){
        return &RECEIVER::receive_data;
    }
};
1
eyllanesc 20 nov. 2018 à 09:18