C++ std::成员函数指针的映射?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1924844/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:36:38  来源:igfitidea点击:

std::map of member function pointers?

c++stl

提问by Goles

I need to implement an std::mapwith <std::string, fn_ptr>pairs. The function pointers are pointers to methods of the same class that owns the map. The idea is to have direct access to the methods instead of implementing a switch or an equivalent.

我需要实现一个std::mapwith<std::string, fn_ptr>对。函数指针是指向拥有映射的同一类的方法的指针。这个想法是直接访问这些方法,而不是实现 switch 或等效项。

( I am using std::stringas keys for the map )

(我std::string用作地图的键)

I'm quite new to C++, so could anyone post some pseudo-code or link that talks about implementing a map with function pointers? ( pointers to methods owned by the same class that owns the map )

我对 C++ 很陌生,所以有人可以发布一些伪代码或链接来讨论使用函数指针实现映射吗?(指向拥有地图的同一类所拥有的方法的指针)

If you think there's a better approach to my problem, suggestions are also welcome.

如果您认为有更好的方法可以解决我的问题,也欢迎提出建议。

回答by

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;
}

回答by outis

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 newAis 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.

这要求用于确定newA调用哪个的值在编译时是已知的。您可以使用 aconst char *作为模板参数,但不能保证在所有编译器上都可以使用。

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 enumrather 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 enumkey 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.

此外,如果您使用一个enum而不是字符串作为键类型,则无需担心检查映射中是否存在键。虽然有人可能将无效的enum密钥传递给newA,但他们必须明确地强制转换参数,这意味着他们不会意外地这样做。我很难想象有人会故意造成崩溃的情况newA;潜在的场景涉及安全性,但应用程序程序员可能会在不使用您的类的情况下使应用程序崩溃。

回答by skypHyman

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:

从 C++14 开始,我们可以使用泛型 lambda 轻松摆脱指向成员方法的指针。
它遵循由通用 lambda 函数组成的前向函数的最小工作示例:

#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{});
}

回答by axs6791

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

另一种选择是使用委托来反对函数指针。这个委托实现非常快,支持多态,并且可以很好地与 stl 容器配合使用。你可以有类似的东西:

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;    
};