Jonathan Layduhur
Jonathan Layduhur

Reputation: 93

Function pointers on a class's member function

void Parser::add_func_no_arg(void (Virtual_Machine::*f)(), std::string comand)
{
    command_no_arg.push_back(comand);
    func_no_arg.push_back(f);
}

void Parser::prepare()
{
    //add_func_no_arg(Virtual_Machine::dump,"dump"); it work when i put it in static but i cant do that
    add_func_no_arg(vm.clear,"clear"); // ERROR HERE the vm.clear does not fit
}

I have those two functions to try help my create a array of pointers func_no_arg; I can't put the vm's func in static; Why cant i have a pointer on a function when it is "trap" whit in one objet ? maybe the type is wrong, here is some .hpp :

class Parser {
    public:
       /***/
        void prepare();
        void add_func_no_arg(void (Virtual_Machine::*f)(), std::string comand);

    private:
        Virtual_Machine vm;
        std::vector<std::string> command_no_arg;
        std::vector<void (Virtual_Machine::*)()> func_no_arg;
        /***/

};


class Virtual_Machine {
    public:
      /***/
        void clear();
      /***/
}

and the compiler said this :

Parser.cpp: In member function ‘void Parser::prepare()’:
Parser.cpp:65:36: error: invalid use of non-static member function ‘void Virtual_Machine::clear()’
     add_func_no_arg(vm.clear,"dump");
                                    ^
In file included from ../include/Parser.hpp:13,
                 from Parser.cpp:8:
../include/VM.hpp:23:14: note: declared here
         void clear();

Upvotes: 1

Views: 121

Answers (3)

Phantomas
Phantomas

Reputation: 206

As mentioned above, the proper syntax to get a pointer to a member functions is &Class::member. The general idea behind this, is that when you declare a class, every function and types in that class belongs in a namespace named after your class. Thus the syntax for getting a pointer to member function is actually equivalent to any pointer to a function inside a namespace. Do keep in mind that access specifier still apply when trying to retrieve a pointer to a function in a class.

However, there is one big difference, in that when you declare a member function, an implicit parameter is added (this in c++), which you actually noted, which is why the type is return_type (Class::*) (parameters)

There are two way to handle this matter. The first one, as noted by others here is to use the instance when you need to call the function, by using the .* or ->* syntax (the dot or arrow are there to access the instance "internals", and the star to de-reference the function pointer). Another way of doing this (mostly if you don't care about the object, or can't access it when you call it) is to wrap your function in an std::function, by "binding" the implicit this, and any parameter you need to, using std::bind. By using std::function and std::bind together, you would be able to use the c-style syntax you're used to.

The example section for std::function and std::bind on cppreference show how to achieve this

Upvotes: 0

Stefan Scheller
Stefan Scheller

Reputation: 953

As written by IlCapitano you have to use a specific syntax to deal with pointer-to-members. Here is an example (compiled with g++ tmp.cpp -o tmp):

#include <iostream>
#include <string>
#include <vector>

class Virtual_Machine
{
    private:
        std::string name;

    public:
        Virtual_Machine(std::string n) : name(n) {}
        void clear() { std::cout << "Clear " << name << std::endl; }
};

class Parser
{
    private:
        Virtual_Machine vm;
        std::vector<std::string> command_no_arg;
        std::vector<void (Virtual_Machine::*)()> func_no_arg;

    public:
        Parser(std::string vm_name) : vm(vm_name) {}
        void add_func_no_arg(void (Virtual_Machine::* f)(), std::string command)
        {
            command_no_arg.push_back(command);
            func_no_arg.push_back(f);
        }
        void prepare()
        {
            add_func_no_arg(&Virtual_Machine::clear, "clear");
        }
        void test()
        {
            (vm.*(func_no_arg[0]))();
        }
};

int main()
{
    Parser a("vm_a"), b("vm_b");

    a.prepare();
    b.prepare();

    a.test();
    b.test();

    return 0;
}

The output of the program is:

Clear vm_a
Clear vm_b

A pointer to the member function clear of an instance of class Virtual_Machine is created with &Virtual_Machine::clear. To later call this function you have to use the operators .* or ->* with an instance of the class on the left side of the operator and the pointer to the function on the right side, like (vm.*(func_no_arg[0]))(). If the function would have parameters, you would place them in the most right pair of parentheses.

Upvotes: 0

IlCapitano
IlCapitano

Reputation: 2094

The syntax for getting a pointer-to-member is &Virtual_Machine::clear (not vm.clear), and a variable f of this type can be invoked on an instance of Virtual_Machine with the .* operator (e.g. vm.*f()).

Alternatively you could write &decltype(vm)::clear, which doesn't depend on the class name.

Upvotes: 1

Related Questions