我确实了解C ++ lambda或C函数指针,但是我不知道如何将它们混合在一起。我已经找到Mixing C++ instance methods with C callback functions了,但是它不符合我的需求。
我有一个包含C标头的C ++类,
extern "C" {
#include <jack/jack.h>
#include <jack/types.h`enter code here`>
#include <jack/ringbuffer.h>
#include <jack/midiport.h>
}
#include <QDialog>
#include <QFile>
#include <QString>
#include "Cliente.h"
class FormQStudio : public QDialog
{
Q_OBJECT
public:
explicit FormQStudio(QWidget *parent = nullptr);
~FormQStudio();
void playMIDIFile(QString file) noexcept(false);
int theCallback(jack_nframes_t nframes, void *arg);
};
C标头定义了一些类型:
typedef uint32_t jack_nframes_t;
typedef int (*JackProcessCallback)(jack_nframes_t nframes, void *arg);
int jack_set_process_callback (jack_client_t *client,
JackProcessCallback process_callback,
void *arg) JACK_OPTIONAL_WEAK_EXPORT;
我的C ++类的实现需要将theCallback(jack_nframes_t nframes, void *arg)
作为参数传递给C函数jack_set_process_callback
。但是我不知道该怎么做。
#include "FormQStudio.h"
FormQStudio::FormQStudio(QWidget *parent) :
QDialog(parent),
ui(new Ui::FormQStudio)
{
ui->setupUi(this);
}
void FormQStudio::playMIDIFile(QString file) noexcept(false){
smf_t *smf = smf_load(file.toUtf8());
smf_event_t *event;
Cliente *c = new Cliente("QStudio");
c->inicializarCliente(
/* HOW TO REFERENCE this->processJackCallback as a parameter? */
);
}
};
“ Cliente”类是这样的:
extern "C" {
#include <jack/jack.h>
#include <jack/types.h>
#include <jack/ringbuffer.h>
#include <jack/midiport.h>
}
#include <QString>
#include <QMap>
#include "ClientePorta.h"
#include "QStageException.h"
class Cliente
{
public:
Cliente(QString clientName);
struct MidiMessage {
jack_nframes_t time;
int len; /* Length of MIDI message, in bytes. */
unsigned char data[3];
};
jack_client_t *getClient();
void conectar(QString portaOrigem, QString clienteDestino, QString portaDestino) noexcept(false);
void inicializarCliente(JackProcessCallback callback) noexcept(false);
void addClientePorta(ClientePorta * cp);
ClientePorta* getClientePorta(QString nomePorta);
void sendMIDI(QString outputPortName, jack_nframes_t nframes ) noexcept(false);
private:
QString clientName;
QString inputPortName;
QString outputPortName;
QMap<QString,ClientePorta*> portas;
jack_client_t *jackClient = NULL;
};
Cliente.cpp是:
#include "Cliente.h"
#include <QDebug>
Cliente::Cliente(QString clientName)
{
this->clientName = clientName;
}
void Cliente::inicializarCliente(JackProcessCallback callback) noexcept(false){
jackClient = jack_client_open(clientName.toUtf8().data(), JackNoStartServer, NULL);
int err = jack_set_process_callback(jackClient, callback , this);
}
};
由于它无关紧要,我将省略其余的实现。我也不是在问lib jack。重点是如何将C ++函数作为参数传递给C回调,如上所示。
答案 0 :(得分:0)
请注意以下事实:jack_set_process_callback
()的最后一个参数是void *
,它会传递给回调函数。
这是C库的一种常见设计模式,可使其在C ++中使用。
您要做的是将要调用其方法的对象的this
作为回调传递给void *
,并将回调指针指向extern "C"
链接包装器函数使用void *
,然后reinterpret_cast
将其返回到类实例指针,然后调用其方法,例如:
extern "C" {
int fwd_callback(jack_nframes_t nframes, void *arg)
{
FormQStudio *p=reintrerpret_cast<FormQStudio *>(arg);
return p->theCallback(nframes);
}
};
// ...
FormQStudio *some_object;
// ...
jack_set_process_callback(client, fwd_callback, reinterpret_cast<void *>(some_object));
当然,当回调被调用时,要确保some_object
仍然存在并且是有效的对象。
答案 1 :(得分:0)
FormQStudio::theCallback
不是函数。这是一个非静态成员函数,这意味着只能通过类型为FormQStudio
的对象来调用它,该对象的指针将以this
的形式传递给该函数。
C对C ++类或类成员一无所知。因此它无法调用此类函数。
此外,应用于&
的{{1}}运算符会产生"pointer-to-member-function"(PMF),它与指向函数的指针完全不同。 (这可能是为什么您看到编译器错误的原因,尽管很难从问题的代码示例中确切知道您尝试了什么。)因此,即使C ++程序也不能将其用作独立的回调,尽管它们可以使用FormQStudio::theCallback
/ .*
语法使用提供的类实例对象引用/指针来调用它。。(注意:如今,最好使用->*
而不是晦涩的运算符。)>
如果事实证明std::invoke
实际上根本没有使用FormQStudio::theCallback
,则将其设为this
。然后,您可以获取其地址并将其用作函数指针。 (尽管我认为不能保证C和C ++函数具有相同的调用约定,所以可以想象,在将其传递给期望回调的C函数时仍然会遇到问题。)