2

I have this function in some library:

class myConsole
{
    void addCommand( std::string command, void* fn );
    ...
}

and in my class I have this function:

void myApp::TestFn( const std::vector<std::string> & args )
{
    // do something
}

in the same class I call this:

void myApp::initApp( )
{
    myConsole::getSingleton( ).addCommand( "FirstTest", &myApp::TestFn );
}

but this gives me this error:

error c2664 cannot convert parameter 2 from 'void(__thiscall myApp::*)(const std::vector<_Ty>&)' to 'void *'

how can I solve this?

thanks in advance!

ghiboz
  • 7,863
  • 21
  • 85
  • 131
  • How do you intend to use `void* fn` afterwards? – Pavel Minaev Jan 05 '12 at 14:19
  • Does `myApp::TestFn` access any member variables of `myApp`? – hmjd Jan 05 '12 at 14:19
  • I need to do something like this: http://www.ogre3d.org/tikiwiki/ConsoleCode&structure=Cookbook – ghiboz Jan 05 '12 at 14:23
  • 2
    You should take a look at Functors, e.g. http://stackoverflow.com/questions/356950/c-functors-and-their-uses – Codemeister Jan 05 '12 at 14:25
  • Do you have control the declaration of myConsole, or is it a library by someone else? Either change it to accept a pointer to an object and a pointer to a member function, or a functor, or a pointer to a global function and a pointer to some arbitrary 'state' (which can just call a member function of the class pointer passed as the state). If not, you will have to (a) accept that it won't be portable if it assumes a function pointer and a void* are interchangeable (this works on many computers/OSes but not all) and (b) accept you need a global object which the command function will always use. – Jack V. Jan 05 '12 at 14:45

3 Answers3

9

You can't solve this. You can't reliably cast a function pointer to void * and back.

(I suggest you redesign the program and stay clear of void*; there's no real need for it in C++.)

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
1

The problem here is that you are trying to pass a class method as it were a void * pointer. This cannot be done.

The right way of doing this is by using templates for the void addCommand (std::string, void *) method. Something like

class myConsole {
    template <typename T>
    void addCommand( std::string command, T f);
};

struct Callback {
    myApp &app;
    Callback (myApp &a) : app(a) {
    }
    void operator() (const std::vector<std::string> &args) {
        app.TestFn(args);
    }
};

void myApp::initApp( )
{
    myConsole::getSingleton( ).addCommand( "FirstTest", Callback(*this) );
}

This gives you the callback principle in C++, but I think you need something more flexible than this solution, since you actually want to choose automatically the command that will be executed by the callback (in this case TestFn).

Dacav
  • 13,590
  • 11
  • 60
  • 87
1

You should avoid void*, especially when trying to use function pointers. I'm going to assume that you are looking only at member-function pointers in the myApp class, and that you are only interested in member-function pointers which take const std::vector<std::string> &args as an argument. This typedef will create the appropriate type and call it MemFunType

typedef void (myApp :: * MemFunType) (const std::vector<std::string> &);

Here is a complete example (on ideone), where there are two different member-functions you may be interested in, TestFn and TestFnBackwards. This example probably isn't very useful, but it gives some examples of member-function pointers.

#include<iostream>
#include<vector>
using namespace std;

struct myApp;

struct myConsole
{
        typedef void (myApp :: * MemFunType) (const std::vector<std::string> &);
            void addCommand( std::string command, MemFunType fn );
};

struct myApp {
        void TestFn( const std::vector<std::string> & args ) {
                cout << " TestFn" << endl;
                for(std :: vector<std::string> :: const_iterator i = args.begin(); i!=args.end(); i++) {
                        cout << *i << endl;
                }
        }
        void TestFnBackwards( const std::vector<std::string> & args ) {
                cout << " TestFnBackwards" << endl;
                for(std :: vector<std::string> :: const_reverse_iterator i = args.rbegin(); i!=args.rend(); i++) {
                        cout << *i << endl;
                }
        }
        static myApp & getSingleton();
} ma;
myApp& myApp :: getSingleton() {
        return ma;
}

void myConsole :: addCommand( std::string , MemFunType fn ) {
        vector<string> words;
        words.push_back("hello");
        words.push_back("world");
        myApp &ma = myApp :: getSingleton();
        (ma.*fn)(words); // execute the member on the singleton object, using the words as the argument.
}

int main() {
        myConsole m;
        m.addCommand( "FirstTest", &myApp::TestFn );
        m.addCommand( "FirstTest", &myApp::TestFnBackwards );
}
Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88
  • thanks, but in this case I need to link in the console class the reference of the myApp class ( and if I have more than one class that call myConsole is hard...) – ghiboz Jan 05 '12 at 16:14
  • @ghiboz, I think you need to edit your question significantly. I would suggest that you stop writing code and try to clearly communicate what your goal is here. Is it true that you want `addCommand` to (in plain English) accept three pieces of information: (1) a reference/pointer to an *instance* of a `myApp`, (2) the name of a member function to be called on that myApp object, (3) the command string ? – Aaron McDaid Jan 05 '12 at 18:57