polapts
polapts

Reputation: 5793

How to use boost::bind correctly with a map of function pointers

I am trying to achieve something like this but getting boost bind related errors

#include <map>
#include "boost/assign.hpp"
#include <boost/foreach.hpp>
#include <string>
#include <boost/function.hpp>
#include <boost/bind.hpp>


struct myStruct_t
{
    int getInt () {return 1;};
};

int foo(  myStruct_t* m, std::string str)
{
    if(str == "A")
    {
        return m->getInt();
    }
    else if (str == "B")
    {
        return 2;
    }
    else
    {
        return 3;
    }
}

typedef std::map<std::string, boost::function<int(myStruct_t*, std::string)> > Map_t;

Map_t myMap = boost::assign::map_list_of    ("Jake", boost::bind((&foo, _1), "A")
                                        ("Ken", boost::bind((&foo, _1), "B")
                                        ("Pete", boost::bind((&foo, _1), "C");



int main ()
{
    std::vector<std::string> myVal;
    myVal.push_back("Jake");
    myVal.push_back("Ken");
    myVal.push_back("Pete");

    myStruct_t myStruct;
    BOOST_FOREACH( const std::string& aStr, myVal)
    {
        Map_t::const_iterator iter = myMap.find(aStr);
        if(iter != myMap.end())
        {
            int myInt = (iter->second)(myStruct);
        }
    }
    return 0;
}

The errors I am getting are

   In file included from /usr/local/boost-1.60.0/include/boost/bind.hpp:22:0,
                 from prog.cc:6:
/usr/local/boost-1.60.0/include/boost/bind/bind.hpp: In instantiation of 'boost::_bi::result_traits<boost::_bi::unspecified, boost::arg<1> >':
/usr/local/boost-1.60.0/include/boost/bind/bind.hpp:1212:48:   instantiated from 'boost::_bi::bind_t<boost::_bi::unspecified, boost::arg<1>, boost::_bi::list1<boost::_bi::value<const char*> > >'
prog.cc:32:81:   instantiated from here
/usr/local/boost-1.60.0/include/boost/bind/bind.hpp:75:37: error: no type named 'result_type' in 'struct boost::arg<1>'
prog.cc:34:82: error: expected ')' before ';' token
prog.cc: In function 'int main()':
prog.cc:50:48: error: no match for call to '(const boost::function<int(myStruct_t*, std::basic_string<char>)>) (myStruct_t&)'
/usr/local/boost-1.60.0/include/boost/function/function_template.hpp:765:17: note: candidate is: result_type boost::function2<R, T1, T2>::operator()(T0, T1) const [with R = int, T0 = myStruct_t*, T1 = std::basic_string<char>, result_type = int]

It seems I am puzzled the way boost::bind is used. Can someone please help me doing it correctly? Many Thanks.

Upvotes: 1

Views: 857

Answers (1)

Richard Hodges
Richard Hodges

Reputation: 69882

The function signature expected at the call site is int(myStruct*)

because of this line (I added the & to remove a logic error):

int myInt = (iter->second)(&myStruct);

in which case the declaration of the map should be:

typedef std::map<std::string, boost::function<int(myStruct_t*)> > Map_t;

Map_t myMap = boost::assign::map_list_of
("Jake", boost::bind(&foo, boost::placeholders::_1, std::string("A")))
("Ken", boost::bind(&foo, boost::placeholders::_1, std::string("B")))
("Pete", boost::bind(&foo, boost::placeholders::_1, std::string("C")));

And then you're good to go.

explanation:

boost[std]::bind returns a function object which is designed to accept only the parameters that are mentioned as placeholders in the bind expression.

This means that the function that is finally called will often have more arguments than the function object returned by bind

so in your case, foo has the following signature:

int foo(  myStruct_t* m, std::string str)

i.e. takes two arguments and returns an int.

However at the point of the call to bind:

boost::bind(&foo, boost::placeholders::_1, std::string("A"))

What we're saying is "capture the function foo and the second argument (a string). Return me a function object that requires one argument (_1) and forward that argument as the first argument to foo while passing the bound string as the second argument.

so given:

auto f = boost::bind(&foo, boost::placeholders::_1, std::string("A"));

f has the signature int f(MyStruct*)

and when called with

auto i = f(&mystruct);

it is equivalent to calling:

auto i = foo(&mystruct, std::string("A"));

Upvotes: 2

Related Questions