首页 文章

将成员函数指针的向量传递给函数

提问于
浏览
0

我编写了一个代码来传递函数指针列表(通过其名称)作为参数 . 但我有错误 . 你能解释为什么我在做 Map 时有错误吗?

#include <functional>
#include <iostream>
#include <string>
#include <vector>
#include <map>

class Foo
{
public:
    void foo(int a, int b)
    {
        std::cout << a <<" "<< b<<'\n';
    }
};

class Bar
{
public:
    void bar(int a, int b)
    {
        std::cout << a<<" "<< b << '\n';
    }
};


int main()
{

    Foo foo;
    Bar bar;
    std::map<std::string,  void (*)(int,int)>myMap;
    myMap["bar"] = &Bar::bar;
    myMap["foo"] = &Foo::foo;

    std::vector<std::function<void (int )>> listofName;
    std::string s1("bar");
    std::string s2("foo");

    listofName.push_back(bind(myMap[s1],&bar,std::placeholders::_1,1));
    listofName.push_back(bind(myMap[s2],&foo,std::placeholders::_1,3));

    for (auto f : listofName) {
        f(2);
    }

 return 0;
}

错误:

34:18:错误:无法转换'void(Bar ::)(int,int)' to ' std :: map,void(*)(int,int)> :: mapped_type {aka void()(int,int)} '在任务中

35:18:错误:无法转换'void(Foo ::)(int,int)' to ' std :: map,void(*)(int,int)> :: mapped_type {aka void()(int,int)} '在任务中

41:70:错误:没有匹配函数调用'std :: vector> :: push_back(std :: _ Bind_helper&)(int,int),Bar,const std :: _ Placeholder <1>&,int> :: type )”

3 回答

  • 0

    成员函数需要知道它们是哪个对象,以便它们可以在正确的 this 上运行 .

    因此,您需要确保您在 Map 中存储的功能知道它将来成为哪个对象 .

    int main() {
      using namespace std::placeholders;
      Foo foo;
      Bar bar;
      std::map<std::string, std::function<void(int, int)>> myMap;
      myMap["bar"] = std::bind(&Bar::bar, &bar, _1, _2);
      myMap["foo"] = std::bind(&Foo::foo, &foo, _1, _2);
    

    后来它已经知道它是什么对象的成员,你不需要再告诉它了:

    // ..
      listofName.push_back(std::bind(myMap[s1], _1, 1));
      listofName.push_back(std::bind(myMap[s2], _1, 3));
    
  • 0

    成员函数包含一个指向 this 的隐藏指针 . 旧技术(继承自C)是将成员函数包装在一个静态函数中,该函数获取指向对象的指针 . 这里有什么好处,因为可以安全地将任何指针转换为 void * 并再次返回,您可以告诉静态包装器它的第一个参数是 void * 并将其强制转换为正确的对象指针以使用它 . 当然,如果您将指针传递给其他对象,您将获得未定义的行为 . 但它只需要对原始代码进行最小的更改:

    #include <functional>
    #include <iostream>
    #include <string>
    #include <vector>
    #include <map>
    
    class Foo
    {
    public:
        void foo(int a, int b)
        {
            std::cout << a <<" "<< b<<'\n';
        }
        static void doFoo(void *obj, int a, int b) { // the wrapper
            static_cast<Foo *>(obj)->foo(a, b);
        }
    };
    
    class Bar
    {
    public:
        void bar(int a, int b)
        {
            std::cout << a<<" "<< b << '\n';
        }
        static void doBar(void *obj, int a, int b) { // wrapper again
            static_cast<Bar *>(obj)->bar(a, b);
        }
    };
    
    
    using std::bind;
    
    int main()
    {
    
        Foo foo;
        Bar bar;
        // function will take an additional void *
        std::map<std::string,  void (*)(void*, int,int)>myMap;
        myMap["bar"] = &Bar::doBar;
        myMap["foo"] = &Foo::doFoo;
    
        std::vector<std::function<void (int )>> listofName;
        std::string s1("bar");
        std::string s2("foo");
    
        listofName.push_back(bind(myMap[s1],(void *)&bar,std::placeholders::_1,1));
        listofName.push_back(bind(myMap[s2],(void *)&foo,std::placeholders::_1,3));
    
        for (auto f : listofName) {
            f(2);
        }
    
     return 0;
    }
    

    这样它编译好(在C 11模式下)并按预期给出:

    2 1
    2 3
    
  • 4

    您不能在此类映射中存储成员函数指针:

    std::map<std::string,  void (*)(int,int)>myMap;
    

    你必须将它改为:

    std::map<std::string,  void (Foo::*)(int,int)>myMap;
    

    但是你可以只存储指向Foo类成员的指针 . 所以最好的选择是在这里使用std :: function . 以下是工作代码:

    Live

    #include <functional>
    #include <iostream>
    #include <string>
    #include <vector>
    #include <map>
    
    class Foo
    {
    public:
        void foo(int a, int b)
        {
            std::cout << a <<" "<< b<<'\n';
        }
    };
    
    class Bar
    {
    public:
        void bar(int a, int b)
        {
            std::cout << a<<" "<< b << '\n';
        }
    };
    
    
    int main()
    {
    
        Foo foo;
        Bar bar;
        using namespace std::placeholders;
        std::map<std::string,  std::function<void (int,int)>>myMap;
        myMap["bar"] = std::bind(&Bar::bar, &bar, _1, _2);
        myMap["foo"] = std::bind(&Foo::foo, &foo, _1, _2);
    
        std::vector<std::function<void (int )>> listofName;
        std::string s1("bar");
        std::string s2("foo");
    
        listofName.push_back(bind(myMap[s1], std::placeholders::_1, 1));
        listofName.push_back(bind(myMap[s2], std::placeholders::_1, 3));
    
        for (auto f : listofName) {
            f(2);
        }
    
     return 0;
    }
    

相关问题