I have dug around quite a bit today and have come up empty. Is there any way to store a functor that is returned from a boost::bind with different types? I found an example that used boost::variants but not sure that this is needed. (Foo and Bar have been simplified for simplicity sake)
#include <boost/bind.hpp>
#include <boost/variant.hpp>
#include <boost/function.hpp>
#include <map>
#include <iostream>
template <typename FooType>
struct Foo {
const FooType tmp_value;
Foo(const FooType& tmp_) :
tmp_value(tmp_)
{
}
template<typename Object>
void operator()(Object& operand)
{
std::cout << operand << std::endl;
operand += tmp_value;
}
};
template <typename BarType>
struct Bar {
const BarType tmp_value;
Bar(const BarType& tmp_) :
tmp_value(tmp_)
{
}
template<typename Object>
void operator()(Object& operand)
{
std::cout << operand << std::endl;
operand -= tmp_value;
}
};
typedef boost::variant<
boost::function<void(int32_t)>,
boost::function<void(int64_t)>,
boost::function<void(double)>,
boost::function<void(float)>
> my_functions;
typedef std::map<std::string, my_functions> test_map;
enum test_t {
FOO,
BAR
};
test_map createFunMap() {
test_map result;
for(int i = 0; i < 2; i++) {
switch(i) {
case test_t::FOO: {
std::cout << "In FOO" << std::endl;
Foo<double> p(1.0);
result.insert(std::pair<std::string,
boost::function<void(double)>>
("foo", boost::bind<void>(p, _1)));
break;
}
case test_t::BAR: {
std::cout << "In BAR" << std::endl;
Bar<int32_t> p(1.0);
result.insert(std::pair<std::string,
boost::function<void(int32_t)>>
("bar", boost::bind<void>(p, _1)));
break;
}
default:
std::cout << "just a default" << std::endl;
break;
}
}
return result;
}
int main() {
test_map myMap;
double t = 5.0;
myMap = createFunMap();
std::cout << t << std::endl;
myMap["foo"](t);
std::cout << t << std::endl;
return 0;
}
compiler output:
g++ -Wall --std=c++0x -I. test_ptrs.cc -o test_ptrs
test_ptrs.cc:93:2: error: type 'mapped_type' (aka 'boost::variant<boost::function<void (int)>, boost::function<void (long long)>, boost::function<void (double)>, boost::function<void (float)>,
boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>') does not provide a call operator
myMap["foo"](t);
^~~~~~~~~~~~
1 error generated.
Thanks.
You have polymorphic functors (Foo and Bar).
You want to type erase them for a certain set of operand types. I suggest defining a type-erased functor type for the purpose:
Now you can simply store the function objects directly in the map:
Let's use
at("foo")
instead of["foo"]
to avoid having to makeErasedFunctor
default-constructible:Prints
See it Live On Coliru
For more background see:
Full Sample