I tried to connect my app to OpenViBE through VRPN server. My app works well until I try to add code to connect my app to VRPN server.
My code looks like this:
MainWindow.c code:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtUiTools/QUiLoader>
#include <QFile>
#include <QMessageBox>
#include <QFileDialog>
#include <iostream>
using namespace std;
#include "vrpn_Analog.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
currentImage = 0;
labelSize = ui->label_2->size();
createActions();
openFileDialog();
}
void MainWindow::checkChannels()
{
vrpn_Analog_Remote *vrpnAnalog = new vrpn_Analog_Remote("Mouse0#localhost");
vrpnAnalog->register_change_handler( 0, handle_analog );
}
void VRPN_CALLBACK MainWindow::handle_analog( void* userData, const vrpn_ANALOGCB a )
{
int nbChannels = a.num_channel;
cout << "Analog : ";
for( int i=0; i < a.num_channel; i++ )
{
cout << a.channel[i] << " ";
}
cout << endl;
}
MainWindow.h code:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFileInfoList>
#include "vrpn_Analog.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
void resizeEvent(QResizeEvent *);
private slots:
void openFileDialog();
private:
void checkChannels();
void VRPN_CALLBACK handle_analog( void* userData, const vrpn_ANALOGCB a );
};
#endif // MAINWINDOW_H
With this code, when I try to run my app I get:
error: C3867: 'MainWindow::handle_analog': function call missing argument list; use '&MainWindow::handle_analog' to create a pointer to member
I try to edit code by error advice, but I get another error:
error: C2664: 'vrpn_Analog_Remote::register_change_handler' : cannot convert parameter 2 from 'void (__stdcall MainWindow::* )(void *,const vrpn_ANALOGCB)' to 'vrpn_ANALOGCHANGEHANDLER'
There is no context in which this conversion is possible
I search around, but I don't find any usable solution.
Methods checkChannels and handle_analog I "copy" from this code, where all works fine:
#include <QtCore/QCoreApplication>
#include <iostream>
#include "vrpn_Analog.h"
void VRPN_CALLBACK vrpn_analog_callback(void* user_data, vrpn_ANALOGCB analog)
{
for (int i = 0; i < analog.num_channel; i++)
{
if (analog.channel[i] > 0)
{
std::cout << "Analog Channel : " << i << " / Analog Value : " << analog.channel[i] << std::endl;
}
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
/* flag used to stop the program execution */
bool running = true;
/* VRPN Analog object */
vrpn_Analog_Remote* VRPNAnalog;
/* Binding of the VRPN Analog to a callback */
VRPNAnalog = new vrpn_Analog_Remote("openvibe_vrpn_analog#localhost");
VRPNAnalog->register_change_handler(NULL, vrpn_analog_callback);
/* The main loop of the program, each VRPN object must be called in order to process data */
while (running)
{
VRPNAnalog->mainloop();
}
return 0;
return a.exec();
}
Where I'm doing mistake? Thanks for all replies.
I had a similar error in Visual Studio: "function call missing argument list; use '&className::functionName' to create a pointer to member"..
I was just missing the parenthesis when calling the getter, so className.get_variable_a()
The error message tells you that the argument you provided does not match vrpn_ANALOGCHANGEHANDLER. You didn't show the definition of that. I checked online and it suggested
typedef void (*vrpn_ANALOGCHANGEHANDLER)(void *userdata, const vrpn_ANALOGCB info);
so I'm going with that.
Your code attempts to pass a pointer-to-member-function, which cannot be converted to a pointer-to-function. This is because a pointer-to-member-function can only be called on an object, so it wouldn't know what object to use.
If you look at the code you are "copying off", you will see that vrpn_analog_callback is a free function. However in your code it is a member function. You need to change your code so that the callback is a free function (or a static member function).
If your intent is that the callback should call the member function on the same MainWindow object that you are registering the handler on, then do this:
// In MainWindow's class definition, add this:
static void VRPN_CALLBACK cb_handle_analog( void* userData, const vrpn_ANALOGCB a )
{
static_cast<MainWindow *>(userData)->handle_analog(NULL, a);
}
// In checkChannels()
vrpnAnalog->register_change_handler( this, cb_handle_analog );
You cannot directly call a non-static class method using this callback. This is because the method is expecting to be called with the class this pointer.
If you don't need any data from your class, then just make the method static. If you do need data from the class, you can make a static "stub" that takes the class pointer in the userData parameter and then calls the original method. Something like:
Declaration:
static void VRPN_CALLBACK handle_analog_stub( void* userData, const vrpn_ANALOGCB a );
Definition
void VRPN_CALLBACK MainWindow::handle_analog_stub( void* userData, const vrpn_ANALOGCB a )
{
MainWindow *mainWindow = static_cast<MainWindow*>(userData);
mainWindow->handle_analog(NULL, a);
}
Then when you call the function use:
vrpnAnalog->register_change_handler( this, handle_analog_stub );
(Updated to static_cast to pointer, thanks rpavlik)
Related
I'm using a library which requires me to derive from a class it provides and then override a function.
However, I'm facing a strange situation where changes made within the member function are:
Temporary: they last only in the scope of the member function.
Non-persistent: In an iteration, the changes made in previous iterations are not visible.
For example, if I have a global int variable initialized to 0 which I increment in the member function, it's value pre-increment is 0 and 1 post-increment while within the member function, but always 0 outside the function's scope. Here is an example that demonstrates the problem:
#include <iostream>
#include <thread>
#include <gtkmm.h>
#include <xmlrpc-c/base.hpp>
#include <xmlrpc-c/registry.hpp>
#include <xmlrpc-c/server_abyss.hpp>
class TestWindow : public Gtk::Window {
public:
TestWindow();
// Called from worker thread
void notify(void (*callback)());
//Dispatcher handler
void on_notification_from_worker_thread();
//Data
Glib::Dispatcher m_Dispatcher;
//Callback functions
void (*on_notify_callback)();
};
class RpcWorker {
public:
RpcWorker(TestWindow* nw);
TestWindow* window;
RpcWorker* worker;
void start_thread ();
};
RpcWorker::RpcWorker(TestWindow* nw){
window = nw;
}
void foo (){
std::cout << "Foo called" << std::endl;
}
void bar (){
std::cout << "Bar called" << std::endl;
}
class testFunction : public xmlrpc_c::method {
public:
testFunction(TestWindow* nw, RpcWorker* worker);
TestWindow* window;
RpcWorker* worker;
void execute(xmlrpc_c::paramList const& paramList,
xmlrpc_c::value * const retvalP) {
window->notify(bar);
*retvalP = xmlrpc_c::value_int(0);
}
};
testFunction::testFunction(TestWindow* nw, RpcWorker* wk){
window = nw;
worker = wk;
}
void RpcWorker::start_thread() {
std::cout << "Thread started" << std::endl;
xmlrpc_c::registry myRegistry;
xmlrpc_c::methodPtr const testFunctionP(new testFunction(window, this));
myRegistry.addMethod("next.hideMinibuffer", testFunctionP);
xmlrpc_c::serverAbyss myAbyssServer (myRegistry, 8080, "/tmp/xmlrpc_log");
myAbyssServer.run();
}
TestWindow::TestWindow(){
m_Dispatcher.connect(sigc::mem_fun
(*this, &TestWindow::on_notification_from_worker_thread));
on_notify_callback = foo;
}
void TestWindow::notify(void (*callback)()) {
on_notify_callback = callback;
m_Dispatcher.emit();
}
void TestWindow::on_notification_from_worker_thread() {
on_notify_callback();
}
int main(int argc, char *argv[]){
auto app = Gtk::Application::create(argc, argv, "Test.Window");
TestWindow window;
RpcWorker worker = RpcWorker(&window);
std::thread* rpc_worker_thread = new std::thread(&RpcWorker::start_thread, &worker);
return app->run(window);
}
In this example, the on_notify_callback variable in the TestWindow class is initially set to point to function foo but later changed to function bar. Calling the function through the pointer while within the execute method immediately after changing it, function bar is invoked. However, once outside the scope of method execute, on_notify_callback points to foo.
What is causing this situation, and how do I fix it or work around it?
I'm trying to use the TeamSpeak SDK for a personal project in Qt, when I use this code in the main it works fine
It compiles without problem. The problem is when I use it in Qt Mainwindow:
Mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <teamspeak/public_definitions.h>
#include <teamspeak/public_errors.h>
#include <teamspeak/serverlib_publicdefinitions.h>
#include <teamspeak/serverlib.h>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
void onClientConnected(uint64 serverID, anyID clientID, uint64 channelID, unsigned int* removeClientError);
ServerLibFunctions funcs; // it's a struct that have pointer fucntions
};
#endif // MAINWINDOW_H
Mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
funcs.onClientConnected = onClientConnected; // error here
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::onClientConnected(uint64 serverID, anyID clientID, uint64 channelID, unsigned int* removeClientError) {
char* clientName;
unsigned int error;
/* Query client nickname */
if ((error = ts3server_getClientVariableAsString(serverID, clientID, CLIENT_NICKNAME, &clientName)) != ERROR_ok) {
char* errormsg;
if (ts3server_getGlobalErrorMessage(error, &errormsg) == ERROR_ok) {
printf("Error querying client nickname: %s\n", errormsg);
ts3server_freeMemory(errormsg);
}
return;
}
printf("Client '%s' joined channel %llu on virtual server %llu\n", clientName, (unsigned long long) channelID, (unsigned long long)serverID);
/* Example: Kick clients with nickname "BlockMe from server */
if (!strcmp(clientName, "BlockMe")) {
printf("Blocking bad client!\n");
*removeClientError = ERROR_client_not_logged_in; /* Give a reason */
}
}
I've commented on the line I got the error in Mainwindow.cpp
and the error:
cannot convert 'MainWindow::onClientConnected' from type 'void (MainWindow::)(uint64, anyID, uint64, unsigned int*) {aka void (MainWindow::)(long long unsigned int, short unsigned int, long long unsigned int, unsigned int*)}' to type 'void ()(uint64, anyID, uint64, unsigned int) {aka void ()(long long unsigned int, short unsigned int, long long unsigned int, unsigned int)}'
funcs.onClientConnected = onClientConnected;
^
I am using Windows 10 Mingw compiler Qt 5.6.1
how can i use this call back fucntion in oop c++
I solve my problem to use TeamSpeak in Qt I initialize the server in the main.cpp and assign all call back functions in the struct and now I can use any function of the server in the main window for example if I want to show the channels in a text edit i use the function of it in any c++ class or Qt Dialog and I can call it without problems
the code of the main.cpp
// put the fucntion of the call back here
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
char *version;
short abort = 0;
uint64 serverID;
unsigned int error;
int unknownInput = 0;
uint64* ids;
int i;
struct ServerLibFunctions funcs;
/* Initialize all callbacks with NULL */
memset(&funcs, 0, sizeof(struct ServerLibFunctions));
funcs.onClientConnected = onClientConnected;
funcs.onClientDisconnected = onClientDisconnected;
funcs.onClientMoved = onClientMoved;
funcs.onChannelCreated = onChannelCreated;
funcs.onChannelEdited = onChannelEdited;
funcs.onChannelDeleted = onChannelDeleted;
funcs.onServerTextMessageEvent = onServerTextMessageEvent;
funcs.onChannelTextMessageEvent = onChannelTextMessageEvent;
funcs.onUserLoggingMessageEvent = onUserLoggingMessageEvent;
funcs.onClientStartTalkingEvent = onClientStartTalkingEvent;
funcs.onClientStopTalkingEvent = onClientStopTalkingEvent;
funcs.onAccountingErrorEvent = onAccountingErrorEvent;
funcs.onCustomPacketEncryptEvent = nullptr;
funcs.onCustomPacketDecryptEvent = nullptr;
if((error = ts3server_initServerLib(&funcs, LogType_FILE | LogType_CONSOLE | LogType_USERLOGGING, NULL)) != ERROR_ok) {
char* errormsg;
if(ts3server_getGlobalErrorMessage(error, &errormsg) == ERROR_ok) {
printf("Error initialzing serverlib: %s\n", errormsg);
ts3server_freeMemory(errormsg);
}
return 1;
}
MainWindow w;
w.show();
return a.exec();
// use any function to edit server in any c++ class as show chan add chancel and so on
}
use all function to edit the server in any c++ class it will work and i think we don't need to initialize the server more than once in main and we don't need to but it in class and if I want to make a VoIP using Qt GUI we need only the server edit function if there's a better answer please post it Thanks
Edit
another solution is to initialize the struct with the call back functions in main and pass it in Mainwindow or any c++ class in the constructor and use it to initialize server lib of TeamSpeak
Your issue can be simulated with below simple code.
Based on my understanding the function you are trying to assign is a class specific member. So the compiler considers it as a signature mismatch when you are trying to assign.
You may need to write the required functionality in a non class member and then assign. (unless there is a way to allow this assignment).
Make the structure with function inputs as a friend of your functional class as shown below.
#include <iostream>
// common namespace
using namespace std;
//Structure with function pointers.
struct funcPtrStruct
{
public:
void (*func)(int a, float b);
};
//The non member function that address your functionality
void testFuncOne(int a ,float b)
{
//Do something
}
//Class implementation
class Test
{
public:
Test()
{
funcPtrStruct funPtrSt;
//func = &testFunc; //Here the error is shown " a value of type .....can not convert......"
funPtrSt.func = &testFuncOne; //This is working but it is not a class memeber.
}
private:
friend struct funcPtrStruct; //Make the structure of function pointers as your friend.
};
int main() {
return 0;
}
I am developing a DLL that is to be loaded dynamically. In this DLL I need to use some Qt networking components, like QLocalServer and QNetworkAccessManager. To use those, I need to have a Qt event loop running. I've read that QLocalServer could be used without an event loop, but that's not the case with QNetworkAccessManager AFAIK.
I've managed to create and exec a QCoreApplication. Instantiation and execution of the QCoreApplication is done in the same thread and I've made sure that the QCoreApplication is created before any other Qt class is used.
The DLL runs several other threads as well and when I emit signals from those threads, their connected slots are never called, except if connection type = Qt::DirectConnection. I need to avoid synchronous connections, so I need to use Qt::QueuedConnection, right?
The other threads I've mentioned are not QThread's, they are std::thread's or boost::thread's. Reason for it is that this is shared code that needs to run in non-Qt apps as well.
Signals are emitted in the following way: I instantiate a bridge object derived from QObject and with the Q_OBJECT set, so the moc compiler generates signal/slot code from it. From this bridge object, I register callback methods (using boost signals). When 'other' threads then call one of these callbacks, the bridge object then emits a signal, that is connected to a slot in the same class. The idea is that the slot is then executed from the Qt event loop so I can start using the Qt networking classes asynchronously. But the slots are never called. Why?
I've stripped my code to reproduce the problem without the DLL stuff.
main.cpp
#include "bridge.h"
#include "worker.h"
#include <QDebug>
#include <memory>
#include <iostream>
#include <string>
struct MyLibrary
{
public:
MyLibrary()
: myWorker_()
, myQtBridge_(myWorker_)
{
myQtBridge_.start();
myWorker_.start();
}
private:
MyWorker myWorker_;
MyQtBridge myQtBridge_;
};
static std::shared_ptr<MyLibrary> myLibrary;
extern "C" __declspec(dllexport) void __cdecl start(void)
{
try {
myLibrary.reset(new MyLibrary());
} catch (const std::exception& e) {
qCritical() << e.what();
}
}
extern "C" __declspec(dllexport) void __cdecl stop(void)
{
try {
myLibrary.reset();
} catch (const std::exception& e) {
qCritical() << e.what() << '\n';
}
}
// main() is only here to reproduce the problem.
// In a DLL build, the calling application would call the start() and stop()
// functions.
int main(int argc, char *argv[])
{
Q_UNUSED(argc);
Q_UNUSED(argv);
start();
for (;;) {
std::cerr << "Enter q to quit: ";
std::string input;
if (std::getline(std::cin, input) && input == "q") {
break;
}
}
stop();
}
bridge.h
#ifndef BRIDGE_H
#define BRIDGE_H
#include "worker.h"
#include "communicator.h"
#include "qapp.h"
// BOOST includes
#include <boost/bind.hpp>
// Qt includes
#include <QDebug>
class MyQtBridge
{
public:
explicit MyQtBridge(MyWorker& myWorker)
: myWorker_(myWorker) // copy reference to the worker
, coreApplication_() // instantiate QtCoreApplication and exec() it in a thread
, myCommunicator_() // instantiate my Qt communication module
{
myWorker_.onSignal1(boost::bind(&MyQtBridge::onSignal1Handler, this));
}
void start()
{
coreApplication_.start();
}
private:
void onSignal1Handler()
{
qDebug() << "MyQtBridge: calling myCommunicator_.signal1()";
myCommunicator_.signal1();
qDebug() << "MyQtBridge: called myCommunicator_.signal1()";
}
private:
MyWorker& myWorker_;
CoreApplication coreApplication_; // Must be created before MyCommunicator!
MyCommunicator myCommunicator_;
};
#endif // BRIDGE_H
worker.h
#ifndef WORKER_H
#define WORKER_H
// BOOST includes
#include <boost/signals2/signal.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
// STL includes
#include <memory>
// Qt includes
#include <QDebug>
// A dummy worker, just to reproduce the problem
// This code cannot have any dependencies to Qt ( except for QDebug now,... :-D )
class MyWorker
{
public:
typedef boost::signals2::signal<void ()> signal_1_type;
MyWorker()
{
}
// called from main thread
~MyWorker()
{
try {
if (thread_) {
thread_->interrupt();
thread_->join();
qDebug() << "MyWorker thread joined";
thread_.reset();
}
} catch (const std::exception& e) {
qCritical() << e.what();
}
}
boost::signals2::connection onSignal1(const signal_1_type::slot_type& subscriber)
{
return signal_1_.connect(subscriber);
}
void start()
{
if (!thread_) {
thread_.reset(new boost::thread(boost::bind(&MyWorker::run, this)));
qDebug() << "MyWorker thread created";
}
}
private:
void run()
{
for (;;) {
boost::this_thread::interruption_point();
boost::this_thread::sleep(boost::posix_time::seconds(3));
qDebug() << "MyWorker: calling signal_1_()";
signal_1_();
qDebug() << "MyWorker: called signal_1_()";
}
}
private:
std::shared_ptr<boost::thread> thread_;
signal_1_type signal_1_;
};
#endif // WORKER_H
qapp.h
#ifndef QAPP_H
#define QAPP_H
#include <QCoreApplication>
#include <QDebug>
#include <thread>
#include <mutex>
#include <condition_variable>
// Purpose of this class is to get a Qt event loop going.
// Instantiation of the QCoreApplication and calling it's exec() method
// are both done in the same thread (seems to be a requirement).
// The rest of this class is synchronization.
class CoreApplication
{
public:
CoreApplication()
: thread_(&CoreApplication::run, this)
{
// Wait until the QCoreApplication has been created
// This is needed before any other Qt objects are created.
std::unique_lock<std::mutex> lock(mutex_);
cv_app_created_.wait(lock);
}
CoreApplication(const CoreApplication&) = delete;
~CoreApplication()
{
QCoreApplication::instance()->quit();
thread_.join();
}
void start()
{
cv_started_.notify_all();
}
private:
void run()
{
int argc = 0;
char **argv = nullptr;
QCoreApplication app(argc, argv);
qDebug() << "QCoreApplication instantiated";
cv_app_created_.notify_all();
// Wait until we're started
{
std::unique_lock<std::mutex> lock(mutex_);
cv_started_.wait(lock);
}
// blocking call, should return when QCoreApplication::instance()->quit() is called
qDebug() << "CoreApplication:: calling QCoreApplication::exec()";
app.exec();
qDebug() << "CoreApplication:: called QCoreApplication::exec()";
}
private:
std::thread thread_;
std::mutex mutex_;
std::condition_variable cv_app_created_, cv_started_;
};
#endif // QAPP_H
communicator.h
#ifndef COMMUNICATOR_H
#define COMMUNICATOR_H
// Qt includes
#include <QObject>
// This would be the class that uses the Qt networking classes
// It would operate independently, reacting only to signals.
class MyCommunicator : public QObject
{
Q_OBJECT
public:
MyCommunicator();
~MyCommunicator();
// called from MyQtBridge::onSignal1Handler()
void signal1();
signals:
void sigSignal1();
private slots:
void slotSignal1();
};
#endif // COMMUNICATOR_H
communicator.cpp
#include "communicator.h"
// Qt includes
#include <QDebug>
MyCommunicator::MyCommunicator()
{
// Note: the reason for this local signal connection is that
// the signal sigSignal1() is emitted from a
// different thread. The Qt::QueuedConnection flag should make sure that
// the slot slotSignal1() is called in the QCoreApplication thread
auto rc = connect(
this, SIGNAL(sigSignal1())
, this, SLOT(slotSignal1())
, Qt::QueuedConnection
);
qDebug() << "MyCommunicator: connect: " << rc;
}
MyCommunicator::~MyCommunicator()
{
}
// called from MyQtBridge::onSignal1Handler()
void MyCommunicator::signal1()
{
qDebug() << "MyCommunicator: emitting sigSignal1()";
emit sigSignal1();
qDebug() << "MyCommunicator: emitted sigSignal1()";
}
void MyCommunicator::slotSignal1()
{
qDebug() << "MyCommunicator: slotSignal1(), yay!"; // NEVER CALLED!
}
Found the solution thanks to the helpful information provided by code_fodder.
I made the MyCommunicator a member of CoreApplication, instantiate it in the CoreApplication::run method with the QCoreApplication instance as parent and now it works!
I have two classes named IPCBase and DispatchData. Now I want to pass QDataStrean Object drom IPCBase to DispatchData. First I tried to send it directly using Connect Statement. But it is giving error like QDataStream object is not registered in QRegisterMatatype.
edit :: I have refered this link as well
When, where and why use namespace when registering custom types for Qt
So I have done something like
typedef QDataStream* myDataStrem;
Q_DECLARE_METATYPE(myDataStrem)
and then connect statement in another class(DispatchData)
connect(mpThrIPCReceiver, SIGNAL(dispatchReadData(const int&, myDataStrem)),
this, SLOT(onIPCDataReceived(const int&, myDataStrem)));
onIPCDataReceived Slot
void DispatchData::onIPCDataReceived(const int& msgType, myDataStrem dataReceived)
{
// dataReceived >> str1; Here it is giving error
// qDebug()<<"is"<<str1;
MemberFuncPointer f = mIPCCommandMapper.value(msgType);
(this->*f)(*dataReceived);
//This is function pointer which will rout it to respective function depending on the Message type.
and then it will come here
void DispatchData::onStartCountingCycle(QDataStream &dataReceived)
{
int data = 0;
dataReceived >> data; //Here it is crashing
//Giving error like
//pure virtual method called
//terminate called without an active exception
// I have debugged it and here dataReceived is becoming Readonly.
}
It seems like you're passing around a dangling pointer: the data stream seems to not exist anymore by the time the receiving thread gets to it. Even if you extended its lifetime in the source object, it's a bad idea to pass a raw pointer through signal-slot connections. If the source class might vanish while the receiver thread has a pending slot call, you'll still be using a dangling pointer at the receiver. You'd be best served by passing around a QSharedPointer or std::shared_ptr.
The following works, you can of course use any type in the shared pointer.
#include <QtCore>
#include <cstdio>
struct Class : public QObject {
Q_SIGNAL void source(QSharedPointer<QTextStream>);
Q_SLOT void destination(QSharedPointer<QTextStream> stream) {
*stream << "Hello" << endl;
}
Q_OBJECT
};
Q_DECLARE_METATYPE(QSharedPointer<QTextStream>)
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
Class c;
c.connect(&c, &Class::source, &c, &Class::destination, Qt::QueuedConnection);
auto out = QSharedPointer<QTextStream>(new QTextStream(stdout));
emit c.source(out);
QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
*out << "About to exec" << endl;
return app.exec();
}
#include "main.moc"
Output:
About to exec
Hello
On modern Qt (5.6 at least), you don't need to call qRegisterMetatype in this case.
The same using std::shared_ptr:
// https://github.com/KubaO/stackoverflown/tree/master/questions/datastream-pass-37850584
#include <QtCore>
#include <cstdio>
#include <memory>
struct Class : public QObject {
Q_SIGNAL void source(std::shared_ptr<QTextStream>);
Q_SLOT void destination(std::shared_ptr<QTextStream> stream) {
*stream << "Hello" << endl;
}
Q_OBJECT
};
Q_DECLARE_METATYPE(std::shared_ptr<QTextStream>)
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
Class c;
c.connect(&c, &Class::source, &c, &Class::destination, Qt::QueuedConnection);
auto out = std::make_shared<QTextStream>(stdout);
emit c.source(out);
QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
*out << "About to exec" << endl;
return app.exec();
}
#include "main.moc"
#include <QtCore/QCoreApplication>
#include <boost/bind.hpp>
#include <boost/function.hpp>
class button
{
public:
boost::function<void()> onClick;
boost::function<void(int ,double )> onClick2;
};
class player
{
public:
void play(int i,double o){}
void stop(){}
};
button playButton, stopButton;
player thePlayer;
void connect()
{
//error C2298: 'return' : illegal operation on pointer to member function expression
playButton.onClick2 = boost::bind(&player::play, &thePlayer);
stopButton.onClick = boost::bind(&player::stop, &thePlayer);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
connect();
return a.exec();
}
boost::bind(&player::play, &thePlayer)
You need to use placeholders for the two arguments:
boost::bind(&player::play, &thePlayer, _1, _2)
The placeholders allow you to say "I'm only binding certain arguments; other arguments will be provided later."
And if you want create portable code - specify namespace of placeholders directly:
boost::bind( &player::play, &thePlayer, ::_1, ::_2 ); // Placeholders of boost::bind are placed in global namespace.