Search code examples
c++boostbindcompositedereference

Dereference iterator as part of a boost::bind composite chain


I am trying to use bind to produce a function that:

  • Receives a map m
  • returns m.begin()->first

For that I am trying to use boost::bind:

typedef map<int,int>::const_iterator (map<int,int>::*const_begin_end) () const;
bind(&pair<const int,int>::first, bind(static_cast<const_begin_end>(&map<int, int>::begin), _1));

This doesn't work because the result of begin needs to be dereferenced. I thought something like

bind(&pair<const int,int>::first, bind(&operator*, bind(static_cast<const_begin_end>(&map<int, int>::begin), _1)));

But this wouldn't work since there is no global operator*.

Questions:

  • Is it possible to achieve this using boost::bind composite chains? How?
  • More easily readable alternatives?

Solution

  • I highly recommend Boost.Phoenix, it's my go-to library when it comes to writing functors on the fly in C++03. It is a superior alternative to Boost.Bind -- that library is showing its age.

    For instance, Phoenix let us use operators on its functors to represent an actual use of that operator when the functor is called. Thus arg1 + arg2 is a functor that returns the sum of its first two operands. This heavily cuts down on the bind noise. A first attempt could look like:

    bind(&pair<const int, int>::first
         , *bind(static_cast<const_begin_end>(&map<int, int>::begin), arg1)) )
    

    (LWS demo)

    But another strong point of Phoenix is that it comes with some batteries. In our case we're very much interested in <boost/phoenix/stl/container.hpp> because this includes some lazy version of the familiar containers operations, including begin. This is very handy in our case:

    // We don't need to disambiguate which begin member we want anymore!
    bind(&pair<const int, int>::first, *begin(arg1))
    

    (LWS demo)


    As a final note, I'll add that C++11 bind expressions are specified such that pointer-to-members work on anything that uses operator*. So out-of-the-box you can do:

    bind(&pair<const int, int>::first, bind(static_cast<begin_type>(&std::map<int, int>::begin), _1))
    

    (LWS demo)