Home > Enterprise >  Filling member function pointers in unordered_map to lookup functions based on strings
Filling member function pointers in unordered_map to lookup functions based on strings

Time:12-29

I have a class which has certain member functions of different types. Now I am trying to create an unordered_map of these members functions based on a std::string key.

I have got this far that if I create a lambda with no capture then it returns the function pointer to the member function. But I am not able to figure out how to put that address in the unordered_map.

#include <iostream>
#include <unordered_map>

using std::cout;
using std::endl;
using std::string;

typedef void (*DoIt)();

class first
{
    public:
        void func_1(){std::cout<<"print from func1"<<endl;};
        void print_number();
        int update_number();
        string get_name();
        void print_name();
        first(int num, string n){number = num; name = n;};
        ~first(){std::cout<<"print destructing."<<std::endl;};
    private:
        int number;
        string name;
};

void first::print_number()
{
    std::cout<<"number is:"<<number<<endl;
}

int first::update_number()
{
    number = number   1;
    return number;
}

string first::get_name()
{
    return name;
}

void first::print_name()
{
    cout<<"name from print name is :"<<name<<endl;
}

using namespace std;
int main()
{
    first f{6, "JohnDoe"};
    f.func_1();
    f.print_number();
    cout<<"new number is :"<<f.update_number();
    std::cout<<"Hello World."<<std::endl;
    f.print_number();
    cout<<"name is :"<<f.get_name()<<endl;

    auto f1 = [](first& f) { f.print_name();};
    f1(f);
    auto f2 = [](first& f) { f.print_number();};    
    f2(f);
    
    unordered_map<string,DoIt> umap_ptr;
    umap_ptr["ptr_num"] = &f2;
    umap_ptr["ptr_name"] = &f1;
    
    
    unordered_map<string, int> umap;
    umap["p_num"] = 1;
    umap["p_name"] = 2;
    
    for (auto x : umap)
          cout << x.first << " " << x.second << endl;
        
    return 0;
}

CodePudding user response:

THe code is a mishmash of syntax, looking like it's author not sure of precise condition when to use what. Declaring captureless lambda, but using it as capturing ne afterwards in one of problems. Type mismatch and expression type mismatch are also problems.

A possible, but very ineffective solution can be:

// needs to be mutable because print_name isn't const-declared
auto f1 = [=]() mutable  { f.print_name();}; 
f1();
auto f2 = [=]() mutable  { f.print_number();};    
f2();

unordered_map<string,std::function<void()>> umap_ptr;
umap_ptr["ptr_num"] = f2;
umap_ptr["ptr_name"] = f1;

It's ineffective because std::function is a lambda-like wrapper around invocable. In our case it's lambda wrapper around lambda wrapper around member function call here. Acceptable or not, it depends on purpose.

One can use pointer to member , but that would limit map to containing pointers of members belonging only to a single type:

unordered_map<string, void (first::*)()> umap_ptr;
umap_ptr["ptr_num"] = &first::print_number;
umap_ptr["ptr_name"] = &first::print_name;

And call to such would look esoteric.

(f.*umap_ptr["ptr_num"])();

Perhaps the REAL thing you're looking for is an implementation of visitor pattern.

CodePudding user response:

Use utilities from <functional>. Raw pointers are raw - you have to create an actual function at file scope for them. std::function allows adding additional information to the function pointer - like a lambda, or other class, for example.

unordered_map<string, std::function<void()>> umap_ptr;
umap_ptr["ptr_num"] = std::bind(&first::print_name, f);
umap_ptr["ptr_name"] = std::bind(&first::print_number, f);
  • Related