Reputation: 862
I need to design a map, which save all function i may use in the futures.
all the functions will have double
as its return value.
and all function share a common parameters const std::vector<float>&
so i define the map as:
typedef std::function<double(const std::vector<float>&)> func;
std::unordered_map<std::string, func> f_map;
for example. if i have a function looks like:
double func1(const std::vector<float>& v) {
return 0.; // just a demo
}
i can put it into map like this:
f_map.emplace("2015", static_cast<double(*)(const std::vector<float>&)>(func1));
it's ok since i tested it.
but the problem is:
i also have some function like this:
double func2(int a, const std::vector<float>& v) {
return 0.; // just for demo
}
how can i input this kind of function in my map?
std::bind doesnt work if i do like this:
f_map.emplace("2000", static_cast<double(*)(const std::vector<float>&)>(std::bind(func2, 1)));
can you help on this?
and can you give me your advice on how to save function into map better, thanks very much
Upvotes: 3
Views: 2055
Reputation: 38415
Avoiding type casts is better and more safe. The first emplace [1] is valid without static_cast.
You should inform std::bind
where to place the unbound argument with help of placeholders [2]. _1
of the namespace std::placeholders
sets the unbound argument v to be the first argument of the resulting functional object.
If you use not capturing lamba expression, you can store pointers to functions. Pointers take less bytes than std::function
objects. See [3].
#include <functional>
#include <string>
#include <unordered_map>
double func1(const std::vector<float>&) {
return 0.; // just a demo
}
double func2(int, const std::vector<float>&) {
return 0.; // just for demo
}
int main() {
using namespace std::placeholders;
typedef std::function<double(const std::vector<float>&)> func;
std::unordered_map<std::string, func> f_map;
f_map.emplace("2015", func1); // [1]
f_map.emplace("2000", std::bind(func2, 1, _1)); // [2]
// [3]
typedef double(*pfunc)(const std::vector<float>&);
std::unordered_map<std::string, pfunc> f_map2;
f_map2.emplace("2015", func1);
f_map2.emplace("2000", [](const std::vector<float>&v) { return func2(1, v); });
}
Upvotes: 1
Reputation: 118
What you're asking is essentially the same as:
How can I store both int
and float
in a map and use them equally?
Functions with different parameters are simply different. A map can only hold a single type. Suppose you get function "2019", how will you or the compiler ever know what kind of function it is?
There are a couple of ways to solve this problem. The essence is to have them be the same type. With std::bind
you're on the right track. The correct way to use bind with parameters is to use the std::placeholders
.
Say we have this function, double DoThing(int num, std::vector<float>& vec)
, and wish to fill in the first parameter, but leave the second one open for later. We can do:
mymap.emplace("2000", std::bind(&DoThing, 123, std::placeholders::_1));
You are free to shift the placeholder around however you like and add other ones too. If you store the object bind returns and later get it back you can call it like so:
mymap["2000"](vec); //will call DoThing(123, vec)
Also. std::bind
returns an object that holds both the function pointer to DoThing
and any value you prefilled as well. Casting this to a function pointer like you did is not possible. That object is not a problem here since std::function
, the map's contained type, has functionality to also store and, later, be able to call this object correctly.
Simillarly you can use lambda's to achieve the same effect as bind:
mymap.emplace("2000", [](std::vector<float>& vec){ return DoThing(123, vec); });
Other possibilities include unions/variants or other possibly tricky stuff. Though these methods will only make your code more complex if you don't know how to use them, so I don't recommend these.
Upvotes: 3