我编写了一个代码来传递函数指针列表(通过其名称)作为参数。但我有错误。你能解释为什么我在做地图时有错误
#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:错误:无法转换&#39; void(Bar :: )(int,int)&#39; to&#39; std :: map,void(*)(int,int)&gt; :: mapped_type {aka void()(int,int)}&#39;在任务中
35:18:错误:无法转换&#39; void(Foo :: )(int,int)&#39; to&#39; std :: map,void(*)(int,int)&gt; :: mapped_type {aka void()(int,int)}&#39;在任务中
41:70:错误:没有匹配函数来调用&#39; std :: vector&gt; :: push_back(std :: _ Bind_helper&amp;)(int,int),Bar,const std :: _ Placeholder&lt; 1&gt; ;&amp;,int&gt; :: type)&#39;
答案 0 :(得分:4)
会员功能需要知道他们所属的对象是什么,以便他们可以使用正确的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));
答案 1 :(得分:1)
您无法在此类地图中存储成员函数指针:
std::map<std::string, void (*)(int,int)>myMap;
您必须将其更改为:
std::map<std::string, void (Foo::*)(int,int)>myMap;
但是你可以只存储指向Foo类成员的指针。所以最好的选择是在这里使用std :: function。以下是工作代码:
#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;
}
答案 2 :(得分: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