
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