std::map of member function pointers?

前端 未结 4 2010
悲&欢浪女
悲&欢浪女 2020-12-03 01:14

I need to implement an std::map with pairs. The function pointers are pointers to methods of the same class that owns t

相关标签:
4条回答
  • 2020-12-03 01:48

    This is about the simplest I can come up with. Note no error checking, and the map could probably usefully be made static.

    #include <map>
    #include <iostream>
    #include <string>
    using namespace std;
    
    struct A {
        typedef int (A::*MFP)(int);
        std::map <string, MFP> fmap;
    
        int f( int x ) { return x + 1; }
        int g( int x ) { return x + 2; }
    
    
        A() {
            fmap.insert( std::make_pair( "f", &A::f ));
            fmap.insert( std::make_pair( "g", &A::g ));
        }
    
        int Call( const string & s, int x ) {
            MFP fp = fmap[s];
            return (this->*fp)(x);
        }
    };
    
    int main() {
        A a;
        cout << a.Call( "f", 0 ) << endl;
        cout << a.Call( "g", 0 ) << endl;
    }
    
    0 讨论(0)
  • 2020-12-03 01:48

    Since C++14, we can use a generic lambda to get rid easily of pointers to member methods.
    It follows a minimal, working example of a forward function made up with a generic lambda function:

    #include<utility>
    #include<map>
    #include<string>
    #include<iostream>
    
    struct SomeClass { };
    struct SomeOtherClass { };
    
    struct Test {
        void test(SomeClass) { std::cout << "SomeClass" << std::endl; }
        void test(SomeOtherClass) { std::cout << "SomeOtherClass" << std::endl; }
    };
    
    int main() {
        Test test;
    
        auto l = [&test](auto c){ test.test(c); };
        std::map<std::string, decltype(l)> m;
    
        m.emplace("foo", l);
        m.emplace("bar", l);
    
        m.at("foo")(SomeClass{});
        m.at("bar")(SomeOtherClass{});
    }
    
    0 讨论(0)
  • 2020-12-03 02:02

    Another option is to use delegates as oppose to function pointers. This delegate implementation is pretty fast, supports polymorphisms, and plays well with stl containers. You could have something like:

    class MyClass {
    public:
        // defines
        typedef fastdelegate::FastDelegate2<int, int, int> MyDelegate;
        typedef std::map<std::string, MyDelegate> MyMap;
    
        // populate your map of delegates
        MyClass() {
            _myMap["plus"] = fastdelegate::MakeDelegate(this, &Plus);
            _myMap["minus"] = fastdelegate::MakeDelegate(this, &Minus);
        }
    
        bool Do(const std::string& operation, int a, int b, int& res){
            MyMap::const_iterator it = _myMap.find(operation);
            if (it != _myMap.end()){
                res = it.second(a,b);
                return true;
            }
    
            return false; 
        }
    private:
        int Plus (int a, int b) { return a+b; }
        int Minus(int a, int b) { return a-b; }
        MyMap _myMap;    
    };      
    
    0 讨论(0)
  • 2020-12-03 02:06

    A template implementation could look like:

    class Factory {
    public:
        enum which {
            foo, bar, baz
        };
    
        template<which w>
        A* newA(...);
        ...
    };
    template<Factory::which w>
    A* Factory::newA(...) {
        /* default implementation */
        throw invalid_argument();
    }
    template<>
    A* Factory::newA<Factory::foo>(...) {
        /* specialization for a 'foo' style A */
        ...
    }
    ....
    

    This requires that the value used to determine which newA is called be known at compile time. You could potentially use a const char * as the template parameter, but it's not guaranteed to work on all compilers.

    Yet another option is to create helper factories, one for each factory creation method, and store those in the map. This isn't a huge advantage over storing method pointers, but does let you define a default creation method and simplifies fetching things from the map (there's no need to check that the key exists, because you'll get a default factory). On the downside, an entry for each unknown key would be added to the map.

    Also, if you use an enum rather than a string for the key type, you shouldn't need to worry about checking whether a key exists in the map. While it's possible for someone to pass an invalid enum key to newA, they'd have to explicitly cast the argument, which means they're not going to do it by accident. I'm having a hard time imagining a case where someone would purposefully cause a crash in newA; the potential scenarios involve security, but an application programmer could crash the app without using your class.

    0 讨论(0)
提交回复
热议问题