Search code examples
c++unordered-mappointer-to-member

How can i call class function with its name in c++


Problem: I have to call functions with its callee names in class. I tried function-pointer with map by return the pointer of functions in class, but it seemed that compiler doesn't allow me to do that with the error

'&': illegal operation on bound member function expression

I want to create a class with function bind with tis callee name ,so I run a register function in its constructor function, then I want to run the funcion inside the class with its callee name. I simplify the code with below,

#include <string>
#include <unordered_map>

class MyClass
{
    typedef bool(*fun)(int num);
public:
    MyClass() { MyClass_functionReg(); } // not sure if I can do this
    ~MyClass() {}

    bool exec(std::string command)
    {
        fun function = find(command);
        function(num);
        return true;
    }

private:
    std::unordered_map<std::string, fun> v_map;
    int num;
private:
    bool MyClass_functionReg()
    {
        v_map.emplace("A", &a); // error here
        v_map.emplace("B", &b);
        v_map.emplace("C", &c);
        v_map.emplace("ERROR", &c);
        return true;
    }

    fun find(std::string command)
    {
        if (v_map.find(command) != v_map.end())
        {
            return v_map[command];
        }
        else
        {
            return v_map["ERROR"];
        }
    }

    bool a(int num)
    {
        return true;
    }
    bool b(int num)
    {
        return true;
    }
    bool c(int num)
    {
        return true;
    }
    bool error(int num)
    {
        return true;
    }
};

int main(int argc, char** argv)
{
    MyClass t;
    t.exec("A");
    t.exec("B");

    return true;
}

Is it just a syntax error? How can i fix this? Is there anything wrong with the way I implement this functionality?


Solution

  • There are several issues in your code:

    1. You need to use pointer to method for your fun type:
    typedef bool(MyClass::*fun)(int num);
    
    1. When adding the methods to the map, you need to add the class name qualifier, e.g.:
    v_map.emplace("A", &MyClass::a);
    
    1. When you invoke the method, you need to use the syntax for dereferencing a pointer to method:
    (this->*function)(num);
    

    See fixed version:

    #include <string>
    #include <unordered_map>
    #include <iostream>
    
    class MyClass
    {
        typedef bool(MyClass::*fun)(int num);
    public:
        MyClass() { MyClass_functionReg(); }
        ~MyClass() {}
    
        bool exec(std::string command)
        {
            fun function = find(command);
            (this->*function)(num);
            return true;
        }
    
    private:
        std::unordered_map<std::string, fun> v_map;
        int num;
    private:
        bool MyClass_functionReg()
        {
            v_map.emplace("A", &MyClass::a); // error here
            v_map.emplace("B", &MyClass::b);
            v_map.emplace("C", &MyClass::c);
            v_map.emplace("ERROR", &MyClass::c);
            return true;
        }
    
        fun find(std::string command)
        {
            if (v_map.find(command) != v_map.end())
            {
                return v_map[command];
            }
            else
            {
                return v_map["ERROR"];
            }
        }
    
        bool a(int num)
        {
            std::cout << "MyClass::a" << std::endl;
            return true;
        }
        bool b(int num)
        {
            std::cout << "MyClass::b" << std::endl;
            return true;
        }
        bool c(int num)
        {
            std::cout << "MyClass::c" << std::endl;
            return true;
        }
        bool error(int num)
        {
            std::cout << "MyClass::error" << std::endl;
            return true;
        }
    };
    
    
    int main(int argc, char** argv)
    {
        MyClass t;
        t.exec("A");
        t.exec("B");
        return 0;
    }
    

    Output:

    MyClass::a
    MyClass::b
    

    A side note: main is returning an int (not bool). Returning 0 means there were no errors. See: What should main() return in C and C++?.