boost::lambda::select2nd

Hi! I would like to write code like 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(), l::select2nd(l::_1) *= 6.0); } Is it hard to implement this for boost::lambda? Markus

Hi! I would like to write code like 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(), l::select2nd(l::_1) *= 6.0); } Is it hard to implement this for boost::lambda? Markus
Accessing data members can be done, but it's unfortunately a bit more complicated than: _1.second I just wish . could be overloaded. Example code below. Cheers, Jaakko -------------------- #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. 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; } }; 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::bind(select2nd(), l::_1) << " "); std::cout << std::endl; std::for_each(M.begin(), M.end(), l::bind(select2nd(), l::_1) *= 6.0); std::for_each(M.begin(), M.end(), std::cout << l::bind(select2nd(), 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(select2nd(), l::_1) << " "); std::cout << std::endl; } -------------------

Jaakko Jarvi wrote:
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 ;-)) I tried to write something taking ll_static_cast as an example, but failed to quickly understand the requirements and semantics of lambda_functor* Could You correct/complete the code below? I could not figure out how select2nd_action::apply gets its RET defined :-( Is there some documentation on the functor conventions or on how to extend LL? class select2nd_action { public: template<class RET, class Arg1> static RET apply(Arg1 &a1) { return a1.second; } }; template <class Arg1> inline const lambda_functor< lambda_functor_base< action<1, select2nd_action >, tuple<typename const_copy_argument <const Arg1>::type>
ll_select2nd(const Arg1& a1) { return lambda_functor_base< action<1, select2nd_action >, tuple<typename const_copy_argument <const Arg1>::type> > ( tuple<typename const_copy_argument <const Arg1>::type>(a1)); } best regards, Markus -- Build your own Expression Template Library with Daixtrose! Visit http://daixtrose.sourceforge.net/

Markus Werle wrote:
Jaakko Jarvi wrote:
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 have to repeat my usual advice here, use the correct algorithm (even if it's not standard). template<class It, class F> void for_each_pair(It first, It last, F f) { for(; first != last; ++first) f(first->first, first->second); } for_each_pair(m.begin(), m.end(), std::cout << _2 << " ");

Peter Dimov wrote:
I have to repeat my usual advice here, use the correct algorithm (even if it's not standard).
template<class It, class F> void for_each_pair(It first, It last, F f) { for(; first != last; ++first) f(first->first, first->second); }
for_each_pair(m.begin(), m.end(), std::cout << _2 << " ");
OK, that's a solution. Many thanks, Markus -- Build your own Expression Template Library with Daixtrose! Visit http://daixtrose.sourceforge.net/

<posted & mailed> Markus Werle wrote:
OK, that's a solution.
No it is not :-( still having problems with template functions: #include <iostream> #include <string> #include <vector> #include <map> #include <algorithm> #include "boost/lambda/lambda.hpp" #include "boost/lambda/if.hpp" #include "boost/lambda/exceptions.hpp" #include "boost/lambda/casts.hpp" #include "boost/lambda/algorithm.hpp" #include "boost/lambda/bind.hpp" #include "boost/mpl/select2nd.hpp" template <class T> inline std::string Foo(const T& t) {} template<class It, class F> void for_each_pair(It first, It last, F f) { for(; first != last; ++first) f(first->first, first->second); } double Double(double d) { return 2.0 * d; } int main() { namespace l = boost::lambda; std::map<int, double> M; M[1] = 5.0; M[3] = 7.0; for_each_pair(M.begin(), M.end(), l::bind(&Double, l::_2)); // THIS HERE FAILS TO COMPILE! for_each_pair(M.begin(), M.end(), l::bind(&Foo<std::string>, l::_2)); } Markus -- Build your own Expression Template Library with Daixtrose! Visit http://daixtrose.sourceforge.net/

Markus Werle wrote:
<posted & mailed>
Markus Werle wrote:
OK, that's a solution.
No it is not :-( still having problems with template functions:
[...]
template <class T> inline std::string Foo(const T& t) {}
[...]
// THIS HERE FAILS TO COMPILE! for_each_pair(M.begin(), M.end(), l::bind(&Foo<std::string>, l::_2));
This is a language problem. A function template is treated as if it names an overload set, even when the supplied template arguments limit that set to a single instance. Many compilers accept the code above as an extension. There is an open issue about this problem: http://std.dkuug.dk/jtc1/sc22/wg21/docs/cwg_active.html#115 Workaround: std::string (*pf)(std::string const &) = &Foo; for_each_pair(M.begin(), M.end(), l::bind(pf, l::_2));

Peter Dimov wrote:
Workaround:
std::string (*pf)(std::string const &) = &Foo;
for_each_pair(M.begin(), M.end(), l::bind(pf, l::_2));
... which is a perfect reason for requesting the feature I asked for :-) Well, I use this workaround in some places, but then the code using iterators is as readable like this one, so there is no advantage left for using lamda :-( Anyway thanks for the explanation. Markus -- Build your own Expression Template Library with Daixtrose! Visit http://daixtrose.sourceforge.net/

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; }
participants (3)
-
Jaakko Jarvi
-
Markus Werle
-
Peter Dimov