for_each(a.begin(), a.end(), std::cout << _1 << ' ');
Boost... wow
Will someone explain how boost's for_each works? It apperently can take an expression, and exectute it:
I downloaded the library, but it looks like I will have to read up on tons of boost's types.
Does anyone have a short, simple explaination of how on earth an expression can be passed to a function? Or am I overestimating it?
either for_each is a macro or << is an overloaded operator either returning a reference or a value.
for_each is a STL algorithms that can be implemented as follow.
The real magic thingy is that unassuming _1 placeholder.
_1 is a reference to a global object of type boost::lambda::placeholder1_type.
operator<<() is overloaded to take such an object as a parameter, returning a function object which, when called, do perform the appropriate action.
That is std::cout << _1 returns an object holding a reference to std::cout which, when called with a parameter foo does call operator<<(std::cout, foo).
That 'function call' operator is templated to accept any foo parameter.
Further work is done so that the function object returned can be used as _1 was originally, making further combination, like std::cout << _1 << ' ' possible.
There's a lot more going on behind the scenes - boost::lambda is one of the most complicated libraries in Boost.
template<typename FwdIter, typename Functor>Functor for_each( FwdIter begin, FwdIter end, Functor func){ while(begin != end) func(*begin++); return func;}
The real magic thingy is that unassuming _1 placeholder.
_1 is a reference to a global object of type boost::lambda::placeholder1_type.
operator<<() is overloaded to take such an object as a parameter, returning a function object which, when called, do perform the appropriate action.
That is std::cout << _1 returns an object holding a reference to std::cout which, when called with a parameter foo does call operator<<(std::cout, foo).
That 'function call' operator is templated to accept any foo parameter.
Further work is done so that the function object returned can be used as _1 was originally, making further combination, like std::cout << _1 << ' ' possible.
There's a lot more going on behind the scenes - boost::lambda is one of the most complicated libraries in Boost.
Quote:Original post by Fruny
for_each is a STL algorithms that can be implemented as follow.template<typename FwdIter, typename Functor>Functor for_each( FwdIter begin, FwdIter end, Functor func){ while(begin != end) func(*begin++); return func;}
The real magic thingy is that unassuming _1 placeholder.
_1 is a reference to a global object of type boost::lambda::placeholder1_type.
operator<<() is overloaded to take such an object as a parameter, returning a function object which, when called, do perform the appropriate action.
That is std::cout << _1 returns an object holding a reference to std::cout which, when called with a parameter foo does call operator<<(std::cout, foo).
That 'function call' operator is templated to accept any foo parameter.
Further work is done so that the function object returned can be used as _1 was originally, making further combination, like std::cout << _1 << ' ' possible.
There's a lot more going on behind the scenes - boost::lambda is one of the most complicated libraries in Boost.
Nice reply.
So they overload cout's << stream operator? How is that done without including their own iostream with boost?
Quote:So they overload cout's << stream operator?
If I understand fruny correctly they did not. They've created a templated << operator which takes two arguments (the two sides of the << operator) the first of which can be any type specified by the template parameter, the second of which is of type boost::lambda::placeholder1_type. This operator then returns an reference that when called using the ( ) operator calls operator << passing in as the first arugment what was on the left of the original << operator and on the right whatever was passed to the ( ) operator when it was called.
Quote:Original post by MonderQuote:So they overload cout's << stream operator?
If I understand fruny correctly they did not. They've created a templated << operator which takes two arguments (the two sides of the << operator) the first of which can be any type specified by the template parameter, the second of which is of type boost::lambda::placeholder1_type. This operator then returns an reference that when called using the ( ) operator calls operator << passing in as the first arugment what was on the left of the original << operator and on the right whatever was passed to the ( ) operator when it was called.
Nifty. That does make it seem a lot worse though. For example, x += 10 could not be used as the expression.
Quote:Original post by thedevdan
Nice reply.
So they overload cout's << stream operator? How is that done without including their own iostream with boost?
First, it is not "cout's << stream operator". operator<< is the bitshift operator, which just happen to also be overloaded for std::basic_ostream, of which std::cout is an instance, to do stream output.
But, yes, they do write an overload for basic_ostream (they treat it as a special case, see boost/lambda/detail/operators.hpp). They do refer to the standard iostream classes which are included with your compiler. They do pull some tricks so as not to require you to include the appropriate iostream headers before the boost::lambda headers -- template metaprogramming at its best -- but you still have to include them yourself at some point.
Quote:Original post by FrunyQuote:Original post by thedevdan
Nice reply.
So they overload cout's << stream operator? How is that done without including their own iostream with boost?
First, it is not "cout's << stream operator". operator<< is the bitshift operator, which just happen to also be overloaded for std::basic_ostream, of which std::cout is an instance, to do stream output.
But, yes, they do write an overload for basic_ostream (they treat it as a special case, see boost/lambda/detail/operators.hpp). They do refer to the standard iostream classes which are included with your compiler. They do pull some tricks so as not to require you to include the appropriate iostream headers before the boost::lambda headers -- template metaprogramming at its best -- but you still have to include them yourself at some point.
I know that << is the bitshift operator, I was being more descriptive. Still, it doesn't seem terribly useful as you can't have normal expressions like x += 10. Thanks for you persistent help!
Quote:Nifty. That does make it seem a lot worse though. For example, x += 10 could not be used as the expression.
It sure can, they also made overloads for operator +=.
GNU nano 1.3.2 File: foo.cc Modified#include <iostream>#include <boost/lambda/lambda.hpp>#include <vector>#include <algorithm>using namespace std;using namespace boost::lambda;int main(){ vector<int> vec; vec.push_back(vec.size()); vec.push_back(vec.size()); vec.push_back(vec.size()); vec.push_back(vec.size()); vec.push_back(vec.size()); for_each( vec.begin(), vec.end(), _1 += 10); for_each( vec.begin(), vec.end(), cout << _1 << '\n' ); int sum = 0; for_each( vec.begin(), vec.end(), sum += _1 ); // though you're better off using accumulate() cout << sum << endl;}
There are limitations to what it can do though, you should read the doc for details.
Quote:Original post by FrunyQuote:Nifty. That does make it seem a lot worse though. For example, x += 10 could not be used as the expression.
It sure can, they also made overloads for operator +=.
*** Source Snippet Removed ***
Geeze, they must have worked hard. [wow]
So it works with any single expression using STL/built-in-types (or anything castable to them)?
Still, I definitely see what you mean about fighting the language. I still am confused what _1 evalutates to in 'sum += _1'. I guess it picks up it's value from a previous for_each.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement