Boost logo

Boost Users :

From: Jaakko Jarvi (jajarvi_at_[hidden])
Date: 2003-06-25 10:48:19


> >   std::for_each(M.begin(), M.end(),
> >   std::cout << l::bind(select2nd(), l::_1) << " ");
> Well, that's too complicated ;-)
> _binding_ to a function or functor is the approach
> I wanted to avoid.
> I think that select1st and select2nd (or - to be generic - select<n>)
> could be directly supported by boost::lambda.
> It's so common to have a list/vector of tuples or a std::map
> (yes, its a request for a feature ;-))

Peter suggested a nice solution.
For completeness, below is the ll_select_2nd solution.
There are many ways to do it, but maybe the cleanest is to add a
wrapper function that does the same as bind(select2nd, ...).

That is, you need to write the function object, which was in the
previous posting (I'll repeat it here too), and then a wrapper
function that makes the results of
bind(select2nd, ...) and ll_select_2nd(...) equal.

Cheers, Jaakko

PS. There is very little documentation on the functor conventions.
This will all change in the future, as bind proposal is now part of
the standard TR, and the conventions are spelled out there. They are
different from the current lambda though.
 
Here's the code:

#include "boost/lambda/lambda.hpp"
#include "boost/lambda/bind.hpp"
#include <algorithm>
#include <map>

#include <iostream>

// A function object class that takes returns a second argument of a pair.
// This can be used with bind.

namespace boost {
  namespace lambda {

struct select2nd {

  // Tell LL how to get the return type. Args will be tuple<select2nd, pair<int, double> >,
  // so get the element at index 1.
  template <class Args>
  struct sig {
    typedef typename
      boost::tuples::element<1, Args>::type pair_t;
    typedef typename boost::add_reference<typename pair_t::second_type>::type type;
  };

  template <class T>
  typename boost::add_reference<typename T::second_type>::type
  operator()(T& t) const { return t.second; }
};

    // add a function to do the same thing as bind(select2nd(), x) would do
template <class Arg2>
inline const
lambda_functor<
  lambda_functor_base<
    action<2, function_action<2> >,
      tuple<const select2nd, typename as_lambda_functor<Arg2>::type> > >

ll_select_2nd(const Arg2& a2) {
  return
    lambda_functor_base<
      action<2, function_action<2> >,
      tuple<const select2nd, typename as_lambda_functor<Arg2>::type>
>
  ( tuple<const select2nd,
          typename as_lambda_functor<Arg2>::type> (select2nd(), to_lambda_functor(a2)) );
}

}}

int main()
{

  namespace l = boost::lambda;
  std::map<int, double> M;

  M[1] = 5.0;
  M[3] = 7.0;
  std::for_each(M.begin(), M.end(), std::cout << l::ll_select_2nd(l::_1) << " ");
  std::cout << std::endl;

  std::for_each(M.begin(), M.end(), l::ll_select_2nd(l::_1) *= 6.0);

  std::for_each(M.begin(), M.end(), std::cout << l::ll_select_2nd(l::_1) << " ");
  std::cout << std::endl;

  // alternatively, use bind to refer directly to the data member. You need to
  // spell out the full type of the pair though.
  std::for_each(M.begin(), M.end(),
                l::bind(&std::map<int, double>::value_type::second, l::_1) *= 6.0);

  std::for_each(M.begin(), M.end(), std::cout << l::bind(l::select2nd(), l::_1) << " ");
  std::cout << std::endl;

}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net