Boost.Bind to access std::map elements in std::for

2020-02-09 11:27发布

I've got a map that stores a simple struct with a key. The struct has two member functions, one is const the other not. I've managed calling the const function using std::for_each without any problems, but I've got some problems calling the non-const function.

struct MyStruct {
  void someConstFunction() const;
  void someFunction();
};

typedef std::map<int, MyStruct> MyMap;
MyMap theMap;

//call the const member function
std::for_each(theMap.begin(), theMap.end(),
   boost::bind(&MyStruct::someConstFunction, boost::bind(&MyMap::value_type::second, _1)));

//call the non-const member function
std::for_each(theMap.begin(), theMap.end(),
   boost::bind(&MyStruct::someFunction, boost::bind(&MyMap::value_type::second, _1)));

The call to the const member function works fine, but it seems boost internally expects a const MyStruct somewhere, and thus fails with the following compilation error in MSVC7.1.

boost\bind\mem_fn_template.hpp(151): error C2440: 'argument' : cannot convert from 'const MyStruct *__w64 ' to 'MyStruct *const '

I'd appreciate any help on how to set the template parameters correctly, so bind does recognize the parameters correctly and let me call the non const function.

thanks, Carl

4条回答
Emotional °昔
2楼-- · 2020-02-09 12:00

IIRC, Boost.Bind uses boost::mem_fn for its binding to members capability. Now, if you look at mem_fun (scroll down to the // data member support part), you'll see that it typedefs its result_type as a const&, while is still has overloads of the function call operator supporting the extraction of a non-const member from a non-const argument.

It thus seems that the problem is that this confuses Boost.Bind's return type deduction mechanism. A solution would thus to explicitly tell Bind that the result is not const:

//call the non-const member function
std::for_each(theMap.begin(), theMap.end(),
   boost::bind(&MyStruct::someFunction, 
       boost::bind<MyStruct&>(&MyMap::value_type::second, _1)
   )
);
查看更多
趁早两清
3楼-- · 2020-02-09 12:17

If you are already depend on Boost, you may be willing to check Boost Foreach

BOOST_FOREACH(MyMap::value_type const& val, MyMap)
{
  val.second.someConstFunction();
}

Much much readable, though I don't know about performance issues.

Also note that you can't use templated typed within the macro without "escaping" the , character:

  • either by a typedef before
  • or by using a second pair of parenthesis around the type
查看更多
The star\"
4楼-- · 2020-02-09 12:25

If you find yourself having to do this a lot I recommend you use the Boost.RangeEx library:

#include <boost/range/algorithm/for_each.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/mem_fn.hpp>
#include <map>

struct MyStruct {
  void someConstFunction() const;
  void someFunction();
};

typedef std::map<int, MyStruct> MyMap;
MyMap theMap;

int main()
{
    //call the const member function
    boost::for_each(theMap | boost::adaptors::map_values,
                    boost::mem_fn(&MyStruct::someConstFunction));

    //call the non-const member function
    boost::for_each(theMap | boost::adaptors::map_values,
                    boost::mem_fn(&MyStruct::someFunction));
}

It's been accepted into Boost but it doesn't come with the official distribution yet. Until it does you can download it from the Boost Vault (download link to zip file).

查看更多
时光不老,我们不散
5楼-- · 2020-02-09 12:25

One problem I spotted: the second bind is called for a non function member. second is a data member, not a method of std::pair

查看更多
登录 后发表回答