【问题标题】:Pass a vector of member function pointer to a function将成员函数指针的向量传递给函数
【发布时间】:2017-05-16 18:31:03
【问题描述】:

我编写了一个代码来传递函数指针列表(按其名称)作为参数。但我有错误。你能解释一下为什么我在做地图时出错

#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)' 转换为 'std::map, void (*)(int, int)>::mapped_type {aka void ()(int, int)}' 在赋值中

35:18:错误:无法将 'void (Foo::)(int, int)' 转换为 '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&, int> ::类型)'

【问题讨论】:

  • void (*)(int,int) 没有。 Bar::bar 偷偷地还收了一个Bar 会员。你为什么不直接使用std::function
  • 您正在尝试将指向成员函数的指针分配给指向函数的指针。这不被允许。就是这样。
  • 在将&amp;Bar::bar 放入地图并将其拉回调用之前,请尝试直接调用。 &amp;Bar::bar(2); 有用吗?你认为它会起作用吗?

标签: c++ c++11 pointers dictionary vector


【解决方案1】:

成员函数需要知道它们是哪个对象的成员,这样它们才能对正确的this 进行操作。

因此,您需要确保您存储在地图中的函数知道将来它是哪个对象的成员。

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

【讨论】:

  • 谢谢,正是我需要的
【解决方案2】:

你不能在这样的映射中存储成员函数指针:

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

【讨论】:

  • 谢谢,正是我需要的
【解决方案3】:

成员函数包含一个指向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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-01
    • 2018-12-07
    • 1970-01-01
    • 2021-11-29
    • 2017-01-19
    • 2012-06-27
    相关资源
    最近更新 更多