4

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.

J. Calleja
  • 4,855
  • 2
  • 33
  • 54
Sk1X1
  • 1,305
  • 5
  • 22
  • 50

3 Answers3

17

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

rayryeng
  • 102,964
  • 22
  • 184
  • 193
Justin Hirsch
  • 319
  • 1
  • 3
  • 8
  • I just started back on C++ after a long streak of C#... You saved my bacon x.x – kayleeFrye_onDeck Mar 04 '15 at 01:03
  • 1
    While this is a related error message, and having this answer here might be helpful to some searchers, I think it's important to note that this is not actually related to or a solution to the problem in the question - see the other answers for that. – Ryan Pavlik Jul 08 '15 at 19:11
  • @rpavlik certainly valid for me! I think this is relevant for all us gen-y programmers who grew up on Java, C# and code completion *_* – Evil Washing Machine Feb 09 '16 at 17:36
4

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 );
M.M
  • 138,810
  • 21
  • 208
  • 365
3

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)

The Dark
  • 8,453
  • 1
  • 16
  • 19
  • Specifically, the types of a function pointer and a pointer to a member function are different (because of the `this` pointer, etc.). Also, no need for a C-style cast: you can (should!) do `MainWindow *self = static_cast(userData);`, or if you are allowed to use `auto`, `auto self = static_cast(userData);` (calling such `this`-equivalent pointers in callbacks `self` is a common idiom I've seen). You can call a non-static member or just put your code in there using `self->myMember` to access object members. – Ryan Pavlik Jul 08 '15 at 19:03