我正在尝试创建std::functions
的无序映射。其中键是字符串,您将在其中查找要调用的函数,而该函数是值。
我写了一个小程序:
#include <iostream>
#include <unordered_map>
#include <functional>
#include <string>
void func1()
{
std::cout << "Function1 has been called." << std::endl;
}
int doMaths(int a)
{
return a + 10;
}
int main()
{
std::unordered_map<std::string,std::function<void()>> myMap;
myMap["func1"] = func1;
}
这样编译就可以了,我可以通过以下方式调用函数(但是我不确定这是否是正确的方法):
auto mapIter = myMap.find("func1");
auto mapVal = mapIter->second;
mapVal();
然后调用该函数,但是我认为这是以创建该函数的新副本为代价的吗?如果我错了,请纠正我。
但是,如果我尝试执行以下操作:myMap["doMaths"] = doMaths;
我会收到编译器错误,因为myMap
中的值为std::function<void()>>
而不是std::function<int(int)>>
。我确实在执行以下操作时将其编译了:myMap["doMaths"] = std::bind(doMaths,int());
但是我不知道它实际上在做什么。当我尝试以与func1
相同的方式调用它时,出现编译器错误。
所以我想我有两个问题:
我如何创建一个unordered_map,它将使用任何类型的函数作为其值?以及如何在地图内调用函数而不必复制函数?
答案 0 :(得分:4)
正如eerorika所说,您可以使用std::any
的地图来做到这一点。这是一些示例代码,还显示了如何调用映射中存储的函数指针:
#include <iostream>
#include <unordered_map>
#include <string>
#include <any>
void func1()
{
std::cout << "Function1 has been called.\n";
}
int doMaths(int a)
{
std::cout << "doMaths has been called, a = " << a << "\n";
return a + 10;
}
int main()
{
std::unordered_map<std::string,std::any> myMap;
myMap["func1"] = func1;
auto mapIter = myMap.find("func1");
std::any_cast <void (*) ()> (mapIter->second) ();
myMap["doMaths"] = doMaths;
mapIter = myMap.find("doMaths");
int result = std::any_cast <int (*) (int)> (mapIter->second) (5);
std::cout << result;
}
std:any_cast
将在运行时抛出std::bad_any_cast
异常,如果类型(或本例中的函数签名)不匹配。
请注意:std::any
需要C ++ 17,请参阅:https://en.cppreference.com/w/cpp/utility/any
答案 1 :(得分:1)
如果您知道函数的类型为std::function<void(void)>
,请将其放在std::unordered_map<std::string,std::function<void()>>
中,然后在其中查找。
如果您知道函数的类型为std::function<int(double, char)>
,请将其放在std::unordered_map<std::string,std::function<int(double, char)>>
中,然后在其中查找。
如果您不知道函数的类型,则无法使用它,因此将其存储在地图中也无济于事。
如果您拥有多种类型的功能,那么您还将拥有多种地图。变量模板(或带有静态映射变量的功能模板)可以帮助您拥有任意数量的此类映射,而无需重复任何代码。当然,通过这种方式,您只能拥有全局地图。可以管理此类地图集合的类可能会涉及更多一些,但只有一点点。
答案 2 :(得分:1)
就像保罗说的那样,但语法为std::function
。您可以使用它在地图中放置具有任何签名的函数,甚至包括lambdas:D
#include <vector>
#include <iostream>
#include <functional>
#include <map>
#include <any>
int doMaths(int a)
{
std::cout << "doMaths has been called, a = " << a << "\n";
return a + 10;
}
int main()
{
std::map<std::string, std::any> map;
map["foo"] = std::function<int(int)>([](int a) { return a * 2; });
map["bar"] = std::function<int(int, int)>([](int a, int b) { return a + b; });
map["maths"] = std::function<int(int)>(doMaths);
int a = std::any_cast<std::function<int(int)>>(map["foo"])(4);
int b = std::any_cast<std::function<int(int, int)>>(map["bar"])(4, 5);
int c = std::any_cast<std::function<int(int)>>(map["maths"])(5);
std::cout << a << " " << b << " " << c <<std::endl;
}
投放时请务必小心,您需要知道正确的签名和返回类型。