[iterator + lambda] transform_iterator and lambda expression

I'm again trying to use FP in C++, and having problems. What I wanted to do was: for_each(predecesor(v, g), /* BLL expression */ ); where predecessor(..) returns a pair of 'transform_iterator' instances. The simplest example which illustrates the problem is: struct functor { typedef int result_type; int operator()(int i) const { return i+1; }; }; transform_iterator<functor, vector<int>::iterator> it(v.begin()); (cout << _1)(*it); This does not compile, because operator* of transform_iterator return rvalue which can't be bound to non-const reference that operator() of the lambda expression accepts. Of all workarounds suggsted on BLL docs, only break_const is applicable to my case (I want to pass non-const references to the lambda, so const_parameters won't do), and break_const is scary. It looks like a serious problem with using FP, so I wonder what can be done. Maybe, transform_iterator should have yet another template parameter telling if it should store a value internally, and return reference (i.e. lvalue) in that case? It need not be enabled by default, but functions like my 'predecessor' above would make use of that extra template parameter. - Volodya

On Apr 23, 2004, at 10:04 AM, Vladimir Prus wrote:
I'm again trying to use FP in C++, and having problems. What I wanted to do was:
for_each(predecesor(v, g), /* BLL expression */ );
where predecessor(..) returns a pair of 'transform_iterator' instances. The simplest example which illustrates the problem is:
struct functor { typedef int result_type; int operator()(int i) const { return i+1; }; };
transform_iterator<functor, vector<int>::iterator> it(v.begin()); (cout << _1)(*it);
This does not compile, because operator* of transform_iterator return rvalue which can't be bound to non-const reference that operator() of the lambda expression accepts.
Of all workarounds suggsted on BLL docs, only break_const is applicable to my case (I want to pass non-const references to the lambda, so const_parameters won't do), and break_const is scary.
It looks like a serious problem with using FP, so I wonder what can be done. Maybe, transform_iterator should have yet another template parameter telling if it should store a value internally, and return reference (i.e. lvalue) in that case? It need not be enabled by default, but functions like my 'predecessor' above would make use of that extra template parameter.
Forwarding problem again :( For a limited number of placeholders (up until _3) or so, we could provide the extra overloads to make this problem go away. N-ary operator() requires 2^N overloads, so for current BLL it is feasible, for bind with placeholders up to _9 (or more?) not really. Jaakko

Hi Jaakko,
struct functor { typedef int result_type; int operator()(int i) const { return i+1; }; };
transform_iterator<functor, vector<int>::iterator> it(v.begin()); (cout << _1)(*it);
This does not compile, because operator* of transform_iterator return rvalue which can't be bound to non-const reference that operator() of the lambda expression accepts.
Forwarding problem again :(
Alas.
For a limited number of placeholders (up until _3) or so, we could provide the extra overloads to make this problem go away.
Yes, please! I did not ever tried to write BLL expressions with 3 parameters, so I'd really like perfect forwarding limited for 3 arguments.
N-ary operator() requires 2^N overloads, so for current BLL it is feasible, for bind with placeholders up to _9 (or more?) not really.
Right. I think what is needed is *some* solution which would allow to explore FP, not necessary allow using FP in all situations. Perfect forwarding for 3 arguments looks fine. - Volodya

Vladimir Prus <ghost@cs.msu.su> writes:
Right. I think what is needed is *some* solution which would allow to explore FP, not necessary allow using FP in all situations. Perfect forwarding for 3 arguments looks fine.
FYI, "perfect forwarding" isn't possible in C++ as it stands: template <class T> int f(T&); template <class T> int g(T& x) { return f(x); } template <class T> int g(T const&) { return f(x); } int x = f(1); // error int x = g(1); // OK In "perfect forwarding", argument rvalue-ness is preserved. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

Vladimir Prus <ghost@cs.msu.su> writes:
I'm again trying to use FP in C++, and having problems. What I wanted to do was:
for_each(predecesor(v, g), /* BLL expression */ );
where predecessor(..) returns a pair of 'transform_iterator' instances. The simplest example which illustrates the problem is:
struct functor { typedef int result_type; int operator()(int i) const { return i+1; }; };
transform_iterator<functor, vector<int>::iterator> it(v.begin()); (cout << _1)(*it);
This does not compile, because operator* of transform_iterator return rvalue which can't be bound to non-const reference that operator() of the lambda expression accepts.
Of all workarounds suggsted on BLL docs, only break_const is applicable to my case (I want to pass non-const references to the lambda, so const_parameters won't do), and break_const is scary.
It looks like a serious problem with using FP, so I wonder what can be done. Maybe, transform_iterator should have yet another template parameter telling if it should store a value internally, and return reference (i.e. lvalue) in that case? It need not be enabled by default, but functions like my 'predecessor' above would make use of that extra template parameter.
I brought up this issue a few weeks ago. I was thinking we should be able to write rvalue(_1) or maybe cref(_1) to pass rvalues. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
I brought up this issue a few weeks ago. I was thinking we should be able to write
rvalue(_1)
or maybe
cref(_1)
to pass rvalues.
The problem is that the BPL operator() looks like this: template<class A0> R operator()(A0& a0) AFAIK there's no way to insert a const there, other than providing the full 2^N overload set. -- Daniel Wallin

Daniel Wallin wrote:
David Abrahams wrote:
I brought up this issue a few weeks ago. I was thinking we should be able to write
rvalue(_1)
or maybe
cref(_1)
to pass rvalues.
The problem is that the BPL operator() looks like this:
template<class A0> R operator()(A0& a0)
AFAIK there's no way to insert a const there, other than providing the full 2^N overload set.
True. Any attempt to insert some metafunction in argument type, e.g: R operator()(const_if_requested<A0>::type a0) will break template argument deduction. - Volodya

Vladimir Prus wrote:
I'm again trying to use FP in C++, and having problems. What I wanted to do was:
for_each(predecesor(v, g), /* BLL expression */ );
where predecessor(..) returns a pair of 'transform_iterator' instances. The simplest example which illustrates the problem is:
struct functor { typedef int result_type; int operator()(int i) const { return i+1; }; };
transform_iterator<functor, vector<int>::iterator> it(v.begin()); (cout << _1)(*it);
This does not compile, because operator* of transform_iterator return rvalue which can't be bound to non-const reference that operator() of the lambda expression accepts.
Of all workarounds suggsted on BLL docs, only break_const is applicable to my case (I want to pass non-const references to the lambda, so const_parameters won't do), and break_const is scary.
It looks like a serious problem with using FP, so I wonder what can be done.
How about what Peter Dimov suggested here: http://article.gmane.org/gmane.comp.lib.boost.devel/34663/match=+cref+ Something like: transform_iterator<functor, vector<int>::iterator> it(v.begin()); boost::make_adaptable<void, int>(cout << _1)(*it); -- Daniel Wallin
participants (4)
-
Daniel Wallin
-
David Abrahams
-
Jaakko Jarvi
-
Vladimir Prus