1
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();
E_net4
  • 27,810
  • 13
  • 101
  • 139
  • If it works when you put `Virtual_Machine::clear`, why can't you do that? – user253751 Jul 15 '20 at 08:00
  • because those fuction need an instance to do thing, – Jonathan Layduhur Jul 15 '20 at 08:02
  • @JonathanLayduhur How are you calling the functions in `func_no_arg`? – IlCapitano Jul 15 '20 at 08:27
  • I don't for now but comming form c if it work i expected : func_no_arg[0]() for exemple – Jonathan Layduhur Jul 15 '20 at 08:35
  • @JonathanLayduhur For member functions you need to have an instance to call them (with pointer-to-memer you can use the `vm.*f()` syntax). If you want your functions in `func_no_arg` to be tied to a specific instane of `Virtual_Machine`, you will need to use [`std::function`](https://en.cppreference.com/w/cpp/utility/functional/function) and [lambda expressions](https://en.cppreference.com/w/cpp/language/lambda). – IlCapitano Jul 15 '20 at 08:57

3 Answers3

1

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.

IlCapitano
  • 1,994
  • 1
  • 7
  • 15
0

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.

Stefan Scheller
  • 953
  • 1
  • 12
  • 22
  • thanks man ; i used your solution and i was wondering i i can improuve on the principale if you what too see the following : https://stackoverflow.com/questions/62922933/vector-of-fuctions-pointers-whit-different-prototype-can-i-build-one – Jonathan Layduhur Jul 15 '20 at 20:05
  • @JonathanLayduhur Thanks for accepting my answer! I checked your other question and posted a possible solution. – Stefan Scheller Jul 16 '20 at 07:02
0

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

Phantomas
  • 206
  • 1
  • 6
  • Your "general idea behind this" is wrong. Don't suggest similarities where is no similarity, even if syntax might be similar. There is big difference between namespace and class member. A class of given type can have multiple instances, so the member is where the instance is. Also a big difference between member function and member variable. Member function has a single instance for all classes of the given type. – armagedescu Jul 15 '20 at 10:09
  • Mmmh you're right for variable, thanks for pointing it out, my phrasing was bad, and I'll edit the answer. I was thinking of types here, not variable, my bad. However, my point for functions still stand. There is only one instance of a given function per class, and in that regard, classes act like namespace, and the syntax for retrieving the address of the function is the same, whereas the type of the pointer will be different for non-static functions. – Phantomas Jul 15 '20 at 11:21
  • Also, I disagree when you say that there are no similarities. Namespace and classes both introduce a named scope, which will be used in mangling to prevent name collision. I'm not saying they are identical, both have different purpose, but there are similarities, and it's reflected by what operator and syntax we use to access elements insides their scope. – Phantomas Jul 15 '20 at 11:40
  • For the function it also does not stand. Because function receives hidden parameter on call unlike the namespace. All must be taken into account when using class member pointers, and this is not the case of namespaces. There is categorically NO similarity between class and namespace. Just because it look so it does not mean similar in any mean. – armagedescu Jul 15 '20 at 12:49
  • Also class is not used for prevent name collision. – armagedescu Jul 15 '20 at 12:51
  • Well, I noted your first point in my second paragraph, I'm not sure what is the issue here. I could not make it more clear. > Also class is not used for prevent name collision. Well it still does prevent name collision. Beside it might not be a good practice, but I've seen classes with only static functions used for this specific purpose, so it is used that way, for better or worse. Anyhow, it does not change the fact that when a class is declared, a new scope is created, and said scope prevent name collision, just as namespace do. And that the syntax is the same because of this. – Phantomas Jul 15 '20 at 13:12
  • Dont search for issues. The class is not similar to namespaces in any mean. If there is any similarity when talking about static members, it is not why class exists for. Static member usage is less than 1%, for very specific patterns if used, or even not used at all. That is not the reason of what was class created for. Saying they are similar in any means shows lack of understanding of programming language it self and of programming as such. – armagedescu Jul 15 '20 at 13:38