Search code examples
c++11hashtablefunctor

Hash table of templated functor


I want to create a hastable to member templated functor, I explain. Here is my exemple which does'nt work:

#include <iostream>    
#include <unordered_map>

using namespace std;
class MyFirstClass
{
    int i_;

public:
    MyFirstClass(): i_(0) {}

    void setI(int i) { i_ = i; }
    int getI() { return i_; }
};

class MySecondClass
{
    bool b_;

public:

    MySecondClass(): b_(0) {}

    void setB(bool b) { b_ = b; }
    bool getB() { return b_; }
};

template<class X, void (X::*p)()>
class MyFunctor
{
    X& _x;
public:
    MyFunctor(X& x) : _x( x ) {}
    void operator()() const { (_x.*p)(); }
};

int main(int argc, char *argv[])
{
    unordered_map<string,MyFunctor> myHashTable;

    MyFirstClass first;
    MyFirstClass second;

    myHashTable["int"] = first::setI;
    myHashTable["bool"] = second::setB;

    //
    string key = "bool";
    int value = 1;

    myHashTable[key](value);

    return 0;
}

I have multiple class with their own setter . I would like to be able thanks to the has table and a command {string,int} change the value of the corresponding class.

The previous code is not working for the moment and I am stuck.


Solution

  • There are a few problems with your code, as it stands.

    Firstly, from your example unordered_map<string,MyFunctor> doesn't name a type, because MyFunctor doesn't name a type. You could create a non-template base class with a virtual operator(), and then have MyFunctor inherit from it.

    Second, you aren't using compatible method pointers, MyFirstClass::setI and MySecondClass::setB both take a parameter.

    Third, related to the first, you have to specify the template parameters when constructing an object from a class template. (until c++17's class template deduction guides). You also have ungrammatical syntax that I assume is trying to specify the object argument to the MyFunctor constructor alongside the method-pointer template argument.

    You would have something like

    class MyFunctorBase {
        virtual void operator()(void * i) const = 0;
    }
    
    template<class T, class X, void (X::*p)(T)>
    class MyFunctor : public MyFunctorBase 
    {
        X& _x;
    public:
        MyFunctor(X& x) : _x( x ) {}
        void operator()(void * i) const override { (_x.*p)(*static_cast<T*>(i)); }
    };
    
    int main(int argc, char *argv[])
    {
        unordered_map<string,shared_ptr<MyFunctorBase>> myHashTable;
    
        MyFirstClass first;
        MyFirstClass second;
    
        myHashTable["int"] = make_shared<MyFunctor<int, MyFirstClass, &MyFirstClass::setI>>(first);
        myHashTable["bool"] = make_shared<MyFunctor<bool, MySecondClass, &MySecondClass::setB>>(second);
    
    
        //
        string key = "bool";
        bool value = true;
    
        (*myHashTable[key])(static_cast<void *>(&value));
    
        return 0;
    }
    

    Or, much more easily, use the existing std::function, which does that for you

    int main(int argc, char *argv[])
    {
        unordered_map<string,function<void(void *)>> myHashTable;
    
        MyFirstClass first;
        MyFirstClass second;
    
        myHashTable["int"] = [first](void * i) { first.setI(*static_cast<int *>(i)); };
        myHashTable["bool"] = [second](void * i) { second.setB(*static_cast<bool *>(i)); };
    
    
        //
        string key = "bool";
        bool value = true;
    
        myHashTable[key](static_cast<void *>(&value));
    
        return 0;
    }