Re: [boost] [Bind] How do I get bind to deduce the return type of for_each?

Message: 8 Date: Thu, 15 Apr 2010 10:51:27 +0100 From: "Sylvester-Bradley, Gareth" <Gareth.Sylvester-Bradley@eu.sony.com> To: <boost@lists.boost.org> Subject: Re: [boost] [Bind] How do I get bind to deduce the return type offor_each? Message-ID: <84883B934769D3428C4AE2E403B188800A1A0F9A@GBISE0BASMSX02.eu.sony.com> Content-Type: text/plain; charset="us-ascii"
I have been trying to use Boost.bind to create an 'STL algorithm function object' to pass into another, 'higher order,' STL algorithm (e.g., to pass a for_each into a for_each). However, I am struggling to get bind to deduce the correct return type of the for_each function object.
The following might help:
http://www.boost.org/doc/libs/1_42_0/doc/html/lambda/le_in_details.html# lambda.nested_stl_algorithms
Best regards, Gareth
Thanks a lot for the suggestion, I did take a look at Lambda library, and I saw that it used some extra type information in its STL algorithm wrappers (the 'sig') to help it figure out the return types. However, I am against using the Lambda library for other reasons, I only want to use the bind library. I'd appreciate some specific advice on how to get the type deduction with the Boost.bind library. Or is this just not possible with Boost.bind?

Thomas Jordan wrote:
Thanks a lot for the suggestion, I did take a look at Lambda library, and I saw that it used some extra type information in its STL algorithm wrappers (the 'sig') to help it figure out the return types. However, I am against using the Lambda library for other reasons, I only want to use the bind library. I'd appreciate some specific advice on how to get the type deduction with the Boost.bind library. Or is this just not possible with Boost.bind?
It's not. Boost.Bind only supports function objects with a specific, fixed type. There is no mechanism to tell it that the return type of struct myForEach { template <typename II, typename F> F operator()(II begin, II end, F function) const { return std::for_each(begin, end, function); } }; is the same as its third argument. In this specific case I'd just use struct myForEach { typedef void result_type; template <typename II, typename F> void operator()(II begin, II end, F function) const { std::for_each(begin, end, function); } };

On Fri, Apr 16, 2010 at 3:48 PM, Peter Dimov <pdimov@pdimov.com> wrote:
Thomas Jordan wrote:
Thanks a lot for the suggestion, I did take a look at Lambda library, and I saw that it used some extra type information in its STL algorithm wrappers (the 'sig') to help it figure out the return types. However, I am against using the Lambda library for other reasons, I only want to use the bind library. I'd appreciate some specific advice on how to get the type deduction with the Boost.bind library. Or is this just not possible with Boost.bind?
It's not. Boost.Bind only supports function objects with a specific, fixed type. There is no mechanism to tell it that the return type of
struct myForEach { template <typename II, typename F> F operator()(II begin, II end, F function) const { return std::for_each(begin, end, function); } };
is the same as its third argument. In this specific case I'd just use
struct myForEach { typedef void result_type; template <typename II, typename F> void operator()(II begin, II end, F function) const { std::for_each(begin, end, function); } };
That should work fine, but I was just playing around with this as well, so I'll just share some alternatives to consider. It seems Thomas wants to iterate over the objects in a multidimensional vector while calling a member function on each one. Before getting to boost bind, first, let's consider boost lambda, which has special facilities for embedded STL algorithms. For example, the following iterates over a 2x2 matrix containing objects of type S and calls S::f() on each one. #include <algorithm> #include <vector> #include <boost/lambda/algorithm.hpp> #include <boost/lambda/bind.hpp> #include <boost/range.hpp> using namespace boost; struct S { int f() const {return 0;} }; int main() { typedef std::vector<S> vector_type; typedef std::vector<vector_type> matrix_type; matrix_type a(2, vector_type(2)); { using namespace boost::lambda; std::for_each(a.begin(), a.end(), bind(lambda::ll::for_each(), bind(begin<const vector_type>, _1), bind(end<const vector_type>, _1), protect(bind(&S::f, _1)) ) ); } } This is adapted from the example code (http://tinyurl.com/y7jhu8t) in the lambda documentation. However, the same code can work using boost::bind if you change the block with the for_each call to { std::for_each(a.begin(), a.end(), bind<void>(lambda::ll::for_each(), bind(begin<const vector_type>, _1), bind(end<const vector_type>, _1), protect(bind(&S::f, _1)) ) ); } Note the bind<void>. This overrides bind's type deduction, which doesn't matter in this case, since the result of for_each is ignored anyway. Now, if you needed the result, to my knowledge, TR1 bind can handle argument dependent return types via result_of. However, boost lambda doesn't currently support the TR1 result_of protocol. See Trac ticket 864. So, you would still need to roll your own for_each functor with TR1 bind. Out of curiosity I tried this in c++0x. The following works with g++ 4.5. #include <algorithm> #include <vector> #include <functional> #include <boost/lambda/algorithm.hpp> #include <boost/range.hpp> using namespace boost; struct S { int f() const { return 0; } }; int main() { typedef std::vector<S> vector_type; typedef std::vector<vector_type> matrix_type; matrix_type a(2, vector_type(2)); { using namespace std; using namespace std::placeholders; for_each(a.begin(), a.end(), bind(lambda::ll::for_each(), bind(begin<const vector_type>, _1), bind(end<const vector_type>, _1), [](S x) { x.f(); } ) ); } } Note that std::bind correctly deduces the result type of lambda::ll::for_each due to its use of a decltype-based std::result_of... Or you can just skip bind altogether... { using namespace std; for_each(a.begin(), a.end(), [](vector_type b) { for_each(b.begin(), b.end(), [](S x){ x.f(); }); } ); } Ah, that's nice. :) Daniel Walker

On Fri, Apr 16, 2010 at 2:33 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Fri, Apr 16, 2010 at 3:48 PM, Peter Dimov <pdimov@pdimov.com> wrote:
Thomas Jordan wrote:
Thanks a lot for the suggestion, I did take a look at Lambda library, and I saw that it used some extra type information in its STL algorithm wrappers (the 'sig') to help it figure out the return types. However, I am against using the Lambda library for other reasons, I only want to use the bind library. I'd appreciate some specific advice on how to get the type deduction with the Boost.bind library. Or is this just not possible with Boost.bind?
It's not. Boost.Bind only supports function objects with a specific, fixed type. There is no mechanism to tell it that the return type of
struct myForEach { template <typename II, typename F> F operator()(II begin, II end, F function) const { return std::for_each(begin, end, function); } };
is the same as its third argument. In this specific case I'd just use
struct myForEach { typedef void result_type; template <typename II, typename F> void operator()(II begin, II end, F function) const { std::for_each(begin, end, function); } };
That should work fine, but I was just playing around with this as well, so I'll just share some alternatives to consider.
It seems Thomas wants to iterate over the objects in a multidimensional vector while calling a member function on each one. Before getting to boost bind, first, let's consider boost lambda, which has special facilities for embedded STL algorithms. For example, the following iterates over a 2x2 matrix containing objects of type S and calls S::f() on each one.
#include <algorithm> #include <vector> #include <boost/lambda/algorithm.hpp> #include <boost/lambda/bind.hpp> #include <boost/range.hpp> using namespace boost;
struct S { int f() const {return 0;} };
int main() { typedef std::vector<S> vector_type; typedef std::vector<vector_type> matrix_type; matrix_type a(2, vector_type(2));
{ using namespace boost::lambda; std::for_each(a.begin(), a.end(), bind(lambda::ll::for_each(), bind(begin<const vector_type>, _1), bind(end<const vector_type>, _1), protect(bind(&S::f, _1)) ) ); } }
This is adapted from the example code (http://tinyurl.com/y7jhu8t) in the lambda documentation. However, the same code can work using boost::bind if you change the block with the for_each call to
{ std::for_each(a.begin(), a.end(), bind<void>(lambda::ll::for_each(), bind(begin<const vector_type>, _1), bind(end<const vector_type>, _1), protect(bind(&S::f, _1)) ) ); }
Note the bind<void>. This overrides bind's type deduction, which doesn't matter in this case, since the result of for_each is ignored anyway. Now, if you needed the result, to my knowledge, TR1 bind can handle argument dependent return types via result_of. However, boost lambda doesn't currently support the TR1 result_of protocol. See Trac ticket 864. So, you would still need to roll your own for_each functor with TR1 bind.
Do note, Boost.Phoenix supports that style just fine, and the code would be even more simple yet if you used Phoenix instead of Lambda as Phoenix is a complete and more powerful replacement for Lambda.
participants (4)
-
Daniel Walker
-
OvermindDL1
-
Peter Dimov
-
Thomas Jordan