Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map of boost function of different types?

Tags:

c++

boost

i was wondering if there was a way to do this in C++?

void func1(const std::string& s)
{
std::cout << s << std::endl;
}

void func2(int me)
{
std::cout << me << std::endl;
}

int main()
{
std::map<std::string, boost::function< ??? > > a_map;

a_map["func1"] = &func1;
a_map["func1"]("HELLO");

}

Is there any way to do what i have above using boost function and a map?

like image 608
UberJumper Avatar asked Mar 14 '09 21:03

UberJumper


3 Answers

There are ways to store the functions, the problem is, in order to be able to call the function with the desired argument you'd have to know the calling signature of the function anyways, and if you have that information, you might as well use separate maps, or use a more complicated object than boost::function.

If you're willing to do a bit of work and have a finite number of signatures, you could just do something like this:

class MultiFunc
{
protected:
    MultiFunc() {}

public:
    typedef void (*stringFunc)(const std::string&);
    typedef void (*intFunc)(int);

    static MultiFunc *Create(stringFunc function);
    static MultiFunc *Create(intFunc function);

    virtual void operator()(const string &) { throw exception(); }
    virtual void operator()(int) { throw exception(); }
    virtual ~MultiFunc();
};

class MultiFuncString : public MultiFunc
{
private:
    stringFunc Function;
public:
    MultiFuncString(stringFunc function) : Function(function) {}
    virtual void operator()(const string &arg) { Function(arg); }
};

class MultiFuncInt : public MultiFunc
{
private:
    intFunc Function;
public:
    MultiFuncInt(intFunc function) : Function(function) {}
    virtual void operator()(int arg) { Function(arg); }
};

MultiFunc *MultiFunc::Create(MultiFunc::stringFunc function)
{
    return new MultiFuncString(function);
}
MultiFunc *MultiFunc::Create(MultiFunc::intFunc function)
{
    return new MultiFuncInt(function);
}

void func1(const std::string& s)
{
std::cout << s << std::endl;
}
void func2(int me)
{
std::cout << me << std::endl;
}

int main()
{
    map<string, MultiFunc *> a_map;
    a_map["func1"] = MultiFunc::Create(&func1);
    (*a_map["func1"])("Hello");
    a_map["func2"] = MultiFunc::Create(&func2);
    (*a_map["func2"])(3);

    // Remember to delete the MultiFunc object, or use smart pointers.
}

This outputs:

Hello
3

Unfortunately, you can't make templated virtual functions or you easily generalize this all.

like image 183
Eclipse Avatar answered Oct 13 '22 21:10

Eclipse


You probably can't use the std::map since it is a homogenous container. Try, something like boost::variant (they support the visitor pattern) or boost::tuple

like image 21
dirkgently Avatar answered Oct 13 '22 21:10

dirkgently


What you are trying to do sounds a little weird. Normally, you would have a container be a collection of abstract types or objects or functions with the same signature. Otherwise, how would you know how to call the function when you are iterating the container? I like to make the container a collection of function objects with a known signature, then use Boost.Bind to store closures that call the function with additional arguments.

For example:

typedef boost::function<void, void> Function;
typedef std::map<std::string, Function> Functions;

Functions functions:

void foo()
{
  ...
}

functions["foo"] = foo;

void bar(std::string &s)
{
  ...
}

// binds the value "hello" to the s parameter
functions["bar"] = boost::bind(bar, "hello");
like image 36
1800 INFORMATION Avatar answered Oct 13 '22 19:10

1800 INFORMATION