The following code using Lambda with vector iterators compiles without complaint:
vector<char> v;
find_if(v.begin(), v.end(), _1 == 'x');
Ditto for this code, which uses istream_iterators:
istream_iterator<char> b1(cin);
istream_iterator<char> e1;
find_if(b1, e1, _1 == 'x');
But the same code with istreambuf_iterators gets rejected:
istreambuf_iterator<char> b2(cin);
istreambuf_iterator<char> e2;
find_if(b2, e2, _1 == 'x');
Error messages from VC8 and gcc 4.1.1 are below. Am I doing something wrong, is
there a bug in Lambda regarding istreambuf_iterators, or is this a restriction
that I didn't see documented somewhere?
Thanks,
Scott
VC8 says:
lambda.cpp
D:\Apps\Microsoft Visual Studio 8\VC\INCLUDE\algorithm(87) : error C2664: 'bool
boost::lambda::lambda_functor<T>::operator ()<char>(
A &) const' : cannot convert parameter 1 from 'char' to 'char &'
[Instantiation traceback omitted]
gcc 4.1.1. says:
stl_algo.h:188: error: no match for call to '(
boost::lambda::lambda_functor<
boost::lambda::lambda_functor_base<
boost::lambda::relational_actionboost::lambda::equal_action
, boost::tuples::tuple<
boost::lambda::lambda_functor<
boost::lambda::placeholder<1>
>, const char
>
>
>
) (char)'
stl_algo.h: In function 'istreambuf_iterator
on Sun Jul 22 2007, Scott Meyers
The following code using Lambda with vector iterators compiles without complaint:
vector<char> v; find_if(v.begin(), v.end(), _1 == 'x');
Ditto for this code, which uses istream_iterators:
istream_iterator<char> b1(cin); istream_iterator<char> e1; find_if(b1, e1, _1 == 'x');
But the same code with istreambuf_iterators gets rejected:
istreambuf_iterator<char> b2(cin); istreambuf_iterator<char> e2; find_if(b2, e2, _1 == 'x');
Error messages from VC8 and gcc 4.1.1 are below. Am I doing something wrong, is there a bug in Lambda regarding istreambuf_iterators, or is this a restriction that I didn't see documented somewhere?
The issue is that istreambuf_iterator is an input iterator, not a forward iterator, and thus is allowed to return from operator* by value instead of reference (which it does). http://tinyurl.com/37v98x#lambda.actual_arguments_to_lambda_functors explains the problem and contains a link to a section about workarounds. HTH, -- Dave Abrahams Boost Consulting http://www.boost-consulting.com The Astoria Seminar ==> http://www.astoriaseminar.com
David Abrahams wrote:
The issue is that istreambuf_iterator is an input iterator, not a forward iterator, and thus is allowed to return from operator* by value instead of reference (which it does).
Of course, one has to know this. Note that the code works with istream_iterators, and they are also input iterators.
http://tinyurl.com/37v98x#lambda.actual_arguments_to_lambda_functors explains the problem and contains a link to a section about workarounds.
Technically, yes, it explains the problem, but it makes no mention of the implications for users of standard library iterator types. I, for one, did not know that operator* for istreambuf_iterator may return an rvalue, and I question whether I should be expected to know this. It would be nice if http://www.boost.org/doc/html/lambda/using_library.html#lambda.actual_argume... mentioned the conditions under which using Lambda with standard iterator types might not compile and called out istreambuf_iterator by name. At least then my Googling for information would have been likely to help. For the record, this compiles: find_if(b2, e2, const_parameters(_1 == 'x')); Thanks for the explanation. Scott
on Sun Jul 22 2007, Scott Meyers
David Abrahams wrote:
The issue is that istreambuf_iterator is an input iterator, not a forward iterator, and thus is allowed to return from operator* by value instead of reference (which it does).
Of course, one has to know this. Note that the code works with istream_iterators, and they are also input iterators.
Yes. Note "allowed," not "required." Incidentally, that allowed variation is why "input iterator" can't be an implicitly deduced concept. If vector<T>::insert were to mistakenly deduce an input iterator (single-pass) to be a (multipass) forward iterator, the library could crash or worse.
http://tinyurl.com/37v98x#lambda.actual_arguments_to_lambda_functors explains the problem and contains a link to a section about workarounds.
Technically, yes, it explains the problem, but it makes no mention of the implications for users of standard library iterator types.
True.
I, for one, did not know that operator* for istreambuf_iterator may return an rvalue, and I question whether I should be expected to know this.
I don't know how to judge whether anyone should be expected to know that. It's just a standard property of input iterators, like that they don't support operator+, but maybe it falls below some threshold of reasonable knowledge.
It would be nice if http://www.boost.org/doc/html/lambda/using_library.html#lambda.actual_argume... mentioned the conditions under which using Lambda with standard iterator types might not compile and called out istreambuf_iterator by name. At least then my Googling for information would have been likely to help.
Yes, it would be nice. IIUC not much effort is going into lambda stuff because it's supposed to be replaced by phoenix 2... but if you want to report a bug, please enter a ticket into the Boost trac at http://svn.boost.org; at least it will stand a chance of being addressed.
For the record, this compiles:
find_if(b2, e2, const_parameters(_1 == 'x'));
Thanks for the explanation.
Glad it helped. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com The Astoria Seminar ==> http://www.astoriaseminar.com
David Abrahams wrote:
on Sun Jul 22 2007, Scott Meyers
wrote:
...
It would be nice if http://www.boost.org/doc/html/lambda/using_library.html#lambda.actual_argume... mentioned the conditions under which using Lambda with standard iterator types might not compile and called out istreambuf_iterator by name. At least then my Googling for information would have been likely to help.
Yes, it would be nice.
It might be easier to just make it work by adding the appropriate A const& overloads to lambda_functor, as we did with boost::bind.
on Mon Jul 23 2007, "Peter Dimov"
David Abrahams wrote:
on Sun Jul 22 2007, Scott Meyers
wrote: ...
It would be nice if http://www.boost.org/doc/html/lambda/using_library.html#lambda.actual_argume... mentioned the conditions under which using Lambda with standard iterator types might not compile and called out istreambuf_iterator by name. At least then my Googling for information would have been likely to help.
Yes, it would be nice.
It might be easier to just make it work by adding the appropriate A const& overloads to lambda_functor, as we did with boost::bind.
Aren't we going to run into the forwarding problem (at some arity, anyway)? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com The Astoria Seminar ==> http://www.astoriaseminar.com
David Abrahams wrote:
on Mon Jul 23 2007, "Peter Dimov"
wrote:
...
It might be easier to just make it work by adding the appropriate A const& overloads to lambda_functor, as we did with boost::bind.
Aren't we going to run into the forwarding problem (at some arity, anyway)?
The automatic equivalent of "const_parameters" only requires one additional overload with everything const&. Lambda only supports up to three arguments so even the full 2^N is feasible. boost::bind uses four overloads in the two-arg case and two overloads for three and up.
on Mon Jul 23 2007, "Peter Dimov"
David Abrahams wrote:
on Mon Jul 23 2007, "Peter Dimov"
wrote: ...
It might be easier to just make it work by adding the appropriate A const& overloads to lambda_functor, as we did with boost::bind.
Aren't we going to run into the forwarding problem (at some arity, anyway)?
The automatic equivalent of "const_parameters" only requires one additional overload with everything const&.
Oh, right.
Lambda only supports up to three arguments so even the full 2^N is feasible.
Well, then, I would go for that. But we'd have to get someone who knows BLL to do the work ;-) -- Dave Abrahams Boost Consulting http://www.boost-consulting.com The Astoria Seminar ==> http://www.astoriaseminar.com
David Abrahams wrote: >>>> It might be easier to just make it work by adding the appropriate A >>>> const& overloads to lambda_functor, as we did with boost::bind. ... > Well, then, I would go for that. But we'd have to get someone who > knows BLL to do the work ;-) Yeah. Patch: Index: lambda_functors.hpp =================================================================== RCS file: /cvsroot/boost/boost/boost/lambda/detail/lambda_functors.hpp,v retrieving revision 1.8 diff -u -r1.8 lambda_functors.hpp --- lambda_functors.hpp 6 Jul 2006 13:47:26 -0000 1.8 +++ lambda_functors.hpp 23 Jul 2007 23:44:39 -0000 @@ -148,6 +148,14 @@ >(a, cnull_type(), cnull_type(), cnull_type()); } + template+ typename inherited::template sig >::type + operator()(A const& a) const { + return inherited::template call< + typename inherited::template sig >::type + >(a, cnull_type(), cnull_type(), cnull_type()); + } + template typename inherited::template sig >::type operator()(A& a, B& b) const { @@ -156,6 +164,30 @@ >(a, b, cnull_type(), cnull_type()); } + template + typename inherited::template sig >::type + operator()(A const& a, B& b) const { + return inherited::template call< + typename inherited::template sig >::type + >(a, b, cnull_type(), cnull_type()); + } + + template + typename inherited::template sig >::type + operator()(A& a, B const& b) const { + return inherited::template call< + typename inherited::template sig >::type + >(a, b, cnull_type(), cnull_type()); + } + + template + typename inherited::template sig >::type + operator()(A const& a, B const& b) const { + return inherited::template call< + typename inherited::template sig >::type + >(a, b, cnull_type(), cnull_type()); + } + template typename inherited::template sig >::type operator()(A& a, B& b, C& c) const @@ -165,6 +197,15 @@ >(a, b, c, cnull_type()); } + template + typename inherited::template sig >::type + operator()(A const& a, B const& b, C const& c) const + { + return inherited::template call< + typename inherited::template sig >::type + >(a, b, c, cnull_type()); + } + // for internal calls with env template typename inherited::template sig >::type Test: #include #include int main() { using namespace boost::lambda; int x = 0; int const y = 1; int const z = 2; BOOST_TEST( _1( x ) == 0 ); BOOST_TEST( _1( y ) == 1 ); BOOST_TEST( _1( 2 ) == 2 ); BOOST_TEST( _2( x, x ) == 0 ); BOOST_TEST( _2( x, y ) == 1 ); BOOST_TEST( _2( x, 2 ) == 2 ); BOOST_TEST( _2( 4, x ) == 0 ); BOOST_TEST( _2( 4, y ) == 1 ); BOOST_TEST( _2( 4, 2 ) == 2 ); (_1 = _2)( x, y ); BOOST_TEST( x == y ); (_1 = _2)( x, 3 ); BOOST_TEST( x == 3 ); (_2 = _1)( z, x ); BOOST_TEST( x == z ); (_2 = _1)( 4, x ); BOOST_TEST( x == 4 ); BOOST_TEST( _3( x, x, x ) == x ); BOOST_TEST( _3( x, x, y ) == y ); BOOST_TEST( _3( x, x, 2 ) == 2 ); BOOST_TEST( _3( x, 5, x ) == x ); BOOST_TEST( _3( x, 5, y ) == y ); BOOST_TEST( _3( x, 5, 2 ) == 2 ); BOOST_TEST( _3( 9, 5, x ) == x ); BOOST_TEST( _3( 9, 5, y ) == y ); BOOST_TEST( _3( 9, 5, 2 ) == 2 ); return boost::report_errors(); }
on Mon Jul 23 2007, "Peter Dimov"
David Abrahams wrote:
It might be easier to just make it work by adding the appropriate A const& overloads to lambda_functor, as we did with boost::bind.
...
Well, then, I would go for that. But we'd have to get someone who knows BLL to do the work ;-)
Yeah.
Patch:
Fantastic! I presume you know how to use http://svn.boost.org/trac/boost/newticket ? ;-) -- Dave Abrahams Boost Consulting http://www.boost-consulting.com The Astoria Seminar ==> http://www.astoriaseminar.com
David Abrahams wrote:
on Mon Jul 23 2007, "Peter Dimov"
wrote: David Abrahams wrote:
It might be easier to just make it work by adding the appropriate A const& overloads to lambda_functor, as we did with boost::bind.
...
Well, then, I would go for that. But we'd have to get someone who knows BLL to do the work ;-)
Yeah.
Patch:
Fantastic! I presume you know how to use http://svn.boost.org/trac/boost/newticket ? ;-)
I'll go for "cvs commit" in a few days if Jaakko doesn't mind.
Hi Peter, By all means, go ahead and apply. The patch is a big improvement that should have been done (I should have done, that is) a long time ago. Thanks! Jaakko On Jul 26, 2007, at 1:43 PM, Peter Dimov wrote:
David Abrahams wrote:
on Mon Jul 23 2007, "Peter Dimov"
wrote: David Abrahams wrote:
> It might be easier to just make it work by adding the > appropriate A const& overloads to lambda_functor, as we did with > boost::bind. ... Well, then, I would go for that. But we'd have to get someone who knows BLL to do the work ;-) Yeah. Patch: Fantastic! I presume you know how to use http://svn.boost.org/trac/boost/newticket ? ;-)
I'll go for "cvs commit" in a few days if Jaakko doesn't mind.
participants (4)
-
David Abrahams
-
Jaakko Jarvi
-
Peter Dimov
-
Scott Meyers