Topic: for_each


Author: Eyal Lotem <eyal@hyperroll.com>
Date: Fri, 6 Jul 2001 18:49:57 GMT
Raw View
Pieter Pareit wrote:
>
> "Mark Kerns" <nospam@nospam.com> wrote in message
> news:JKN_6.51418$Mf5.13771000@news3.rdc1.on.home.com...
>> > But for_each returns (a copy of) the modified function object,
>> > therefore you can write
>> >
>> > CAccumulate Accumulate;
>> > Accumulate = for_each(Iter1, Iter2, Accumulate);
>> > int Total = Accumulate.GetTotal();
>>
>> Yes but it's inherently inefficient. The above invokes the copy
> constructor
>> going in and the assignment operator coming back out (reassigning back to
>> itself no less). What's the point of this. It's more efficient and less
>> verbose doing it in-place. Only explicit instantiation allows that
>> however but it's unnatural IMO. Certainly much uglier which degrades
>> legibility
> and
>> hence increases comprehension time. So you're forced to sacrifice
> syntactic
>> cleanliness for efficiency. Not good.
"Syntatic cleanliness" often sacrificies efficiency.  Create useful
resource-sharing copy constructors, that hardly do anything, and use an
optimizing compiler, and hopefully, you won't even notice.  A smart
compiler can even inline the copy construction, and later optimize it out
of the assembly altogether.
>
> Did you take into account the time spend referencing?
That is notime..

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: dietmar_kuehl@yahoo.com (Dietmar Kuehl)
Date: Wed, 27 Jun 2001 17:46:34 GMT
Raw View
Hi,
Howard Hinnant <hinnant@antispam.twcny.rr.com> wrote:
> Unfortunately I believe the standard also will disallow
> the following

Even if the standard disallows this [ugly you have to type the argument
types explicitly] approach, it is pretty simple to create a function object
adaptor which takes a functor reference as argument and stores this
reference internally. Something like this:

  template <typename Func>
  struct ref_func_t:
    public std::unary_function<typename Func::argument_type,
                               typename Func::return_type>
  {
    ref_func_t(Func& func): m_func(func) {}
    typename Func::return_type operator()(typename Func::argument_type& arg)
      const { return m_func(arg); }
    typename Func::return_type operator()(typename Func::argument_type& arg)
      { return m_func(arg); }
   Func& m_func;
  };

  template <typename Func>
  ref_func_t<Func> ref_func(Func& func) { return ref_func_t<Func>(func); }

Just a simple adaptor solving the problem. The other way around, ie. using
a reference for the functors is not easily worked around in general, eg.
because temporary objects cannot be bound to non-const references.
--
<mailto:dietmar_kuehl@yahoo.com> <http://www.dietmar-kuehl.de/>
Phaidros eaSE - Easy Software Engineering: <http://www.phaidros.com/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Christopher Eltschka <celtschk@web.de>
Date: Wed, 27 Jun 2001 19:37:39 GMT
Raw View
"Mark Kerns" <nospam@nospam.com> writes:

> Can anyone tell me why the canonical implementation of "std::for_each"
> appears as the following in every implementation I've looked at so far:
>
> /////////////////////////////////////
> template <class _InputIter, class _Function>
> _Function for_each(_InputIter __first, _InputIter __last, _Function __f) {
>   for ( ; __first != __last; ++__first)
>     __f(*__first);
>   return __f;
> }
> /////////////////////////////////////

[...]

> A) Your function object *must* have a copy constructor (which it should
> anyway if the default won't do)
> B) More importantly, because a copy of your function object will be executed
> instead of the original, the original can't accumulate information on each
> iteration. In other words, if I do something like:
>
> CAccumulate Accumulate;
> for_each(Iter1, Iter2, Accumulate);
> int Total = Accumulate.GetTotal();
>
> This won't work because the "Accumulate" object is passed by value and not
> by reference. The same problem probably applies to other STL implementations
> I'm sure. Any comments and does the standard say anything about this?

But for_each returns (a copy of) the modified function object,
therefore you can write

CAccumulate Accumulate;
Accumulate = for_each(Iter1, Iter2, Accumulate);
int Total = Accumulate.GetTotal();

Or even, if you just need the call of GetTotal (i.e. you don't need
the function object any more after that):

int Total = for_each(Iter1, Iter2, CAccumulate()).GetTotal();

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Wed, 27 Jun 2001 20:21:19 GMT
Raw View
In article <kk8_6.36849$Mf5.9580443@news3.rdc1.on.home.com>, Mark Kerns
<nospam@nospam.com> writes
>CAccumulate Accumulate;
>for_each(Iter1, Iter2, Accumulate);
>int Total = Accumulate.GetTotal();
>
>This won't work because the "Accumulate" object is passed by value and not
>by reference. The same problem probably applies to other STL implementations
>I'm sure. Any comments and does the standard say anything about this?


Well perhaps it is a matter of concept. for_each is designed to deal
with elements of a sequence on an individual basis. We have other
'algorithms' that deal with a sequence as a whole (such as accumulate)

The other option you have is to provide your function object class with
static member(s) into which the data is stashed (though you will have to
reset that before each use)

Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Mirek Fidler" <cxl@volny.cz>
Date: Thu, 28 Jun 2001 18:16:20 GMT
Raw View
> Just a simple adaptor solving the problem. The other way around, ie. using
> a reference for the functors is not easily worked around in general, eg.
> because temporary objects cannot be bound to non-const references.

    Yes ! ;-) Another reason to change it ;-)

Mirek


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Mark Kerns" <nospam@nospam.com>
Date: Thu, 28 Jun 2001 22:37:05 GMT
Raw View
> But for_each returns (a copy of) the modified function object,
> therefore you can write
>
> CAccumulate Accumulate;
> Accumulate = for_each(Iter1, Iter2, Accumulate);
> int Total = Accumulate.GetTotal();

Yes but it's inherently inefficient. The above invokes the copy constructor
going in and the assignment operator coming back out (reassigning back to
itself no less). What's the point of this. It's more efficient and less
verbose doing it in-place. Only explicit instantiation allows that however
but it's unnatural IMO. Certainly much uglier which degrades legibility and
hence increases comprehension time. So you're forced to sacrifice syntactic
cleanliness for efficiency. Not good.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Pieter Pareit" <NOSPAMpieter.pareit@planetinternet.be.be>
Date: Fri, 29 Jun 2001 20:58:35 GMT
Raw View
"Mark Kerns" <nospam@nospam.com> wrote in message
news:JKN_6.51418$Mf5.13771000@news3.rdc1.on.home.com...
> > But for_each returns (a copy of) the modified function object,
> > therefore you can write
> >
> > CAccumulate Accumulate;
> > Accumulate = for_each(Iter1, Iter2, Accumulate);
> > int Total = Accumulate.GetTotal();
>
> Yes but it's inherently inefficient. The above invokes the copy
constructor
> going in and the assignment operator coming back out (reassigning back to
> itself no less). What's the point of this. It's more efficient and less
> verbose doing it in-place. Only explicit instantiation allows that however
> but it's unnatural IMO. Certainly much uglier which degrades legibility
and
> hence increases comprehension time. So you're forced to sacrifice
syntactic
> cleanliness for efficiency. Not good.

Did you take into account the time spend referencing?

pieter;

>
> ---
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
>





======================================= MODERATOR'S COMMENT:
 Please don't overquote.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Mark Kerns" <nospam@nospam.com>
Date: Tue, 26 Jun 2001 23:23:34 GMT
Raw View
Can anyone tell me why the canonical implementation of "std::for_each"
appears as the following in every implementation I've looked at so far:

/////////////////////////////////////
template <class _InputIter, class _Function>
_Function for_each(_InputIter __first, _InputIter __last, _Function __f) {
  for ( ; __first != __last; ++__first)
    __f(*__first);
  return __f;
}
/////////////////////////////////////

Even one of Stroustrup's own examples does it this way. Wouldn't it make
more sense however for the 3rd argument to be passed by reference instead of
by value, assuming of course there's not some subtle mechanical reason
preventing it (since this arg must always properly resolve to something that
can be executed, i.e., a function object or regular function pointer)? I can
see versions taking both a "const" and "non-const" reference argument,
assuming "ambiguous" resolution problems won't occur (I'm not sure at this
point). In any event, the way it stands, if you pass a function object as
the 3rd argument then a copy of the object is passed instead of the
original. Therefore:

A) Your function object *must* have a copy constructor (which it should
anyway if the default won't do)
B) More importantly, because a copy of your function object will be executed
instead of the original, the original can't accumulate information on each
iteration. In other words, if I do something like:

CAccumulate Accumulate;
for_each(Iter1, Iter2, Accumulate);
int Total = Accumulate.GetTotal();

This won't work because the "Accumulate" object is passed by value and not
by reference. The same problem probably applies to other STL implementations
I'm sure. Any comments and does the standard say anything about this?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Howard Hinnant <hinnant@antispam.twcny.rr.com>
Date: Tue, 26 Jun 2001 23:48:42 GMT
Raw View
In article <kk8_6.36849$Mf5.9580443@news3.rdc1.on.home.com>, Mark Kerns
<nospam@nospam.com> wrote:

| Even one of Stroustrup's own examples does it this way. Wouldn't it make
| more sense however for the 3rd argument to be passed by reference instead of
| by value, assuming of course there's not some subtle mechanical reason
| preventing it (since this arg must always properly resolve to something that
| can be executed, i.e., a function object or regular function pointer)? I can
| see versions taking both a "const" and "non-const" reference argument,
| assuming "ambiguous" resolution problems won't occur (I'm not sure at this
| point). In any event, the way it stands, if you pass a function object as
| the 3rd argument then a copy of the object is passed instead of the
| original. Therefore:
|
| A) Your function object *must* have a copy constructor (which it should
| anyway if the default won't do)
| B) More importantly, because a copy of your function object will be executed
| instead of the original, the original can't accumulate information on each
| iteration. In other words, if I do something like:
|
| CAccumulate Accumulate;
| for_each(Iter1, Iter2, Accumulate);
| int Total = Accumulate.GetTotal();
|
| This won't work because the "Accumulate" object is passed by value and not
| by reference. The same problem probably applies to other STL implementations
| I'm sure. Any comments and does the standard say anything about this?

Actually passing by value makes a lot of sense.  Because you can easily
specify what "by value" means via explicit template argument
specification.  Unfortunately I believe the standard also will disallow
the following
(http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-active.html#92).
However, in practice I suspect it will always work for for_each:

#include <iostream>
#include <algorithm>

class CAccumulate
{
public:
   CAccumulate() : sum_(0) {}
   int GetTotal() const {return sum_;}
   void operator()(int x) {sum_ += x;}
private:
   int sum_;

   CAccumulate(const CAccumulate&);
   CAccumulate& operator = (CAccumulate&);
};

int main()
{
   int ia[] = {1, 2, 3};
   int* Iter1 = ia;
   int* Iter2 = ia+3;
   CAccumulate Accumulate;
   std::for_each<int*, CAccumulate&>(Iter1, Iter2, Accumulate);
   int Total = Accumulate.GetTotal();
   std::cout << Total;
}

--
Howard Hinnant

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Mark Kerns" <nospam@nospam.com>
Date: Wed, 27 Jun 2001 16:36:52 GMT
Raw View
Yes, you're right. You can do this by explicit instantiation. However, are
there any reasons why the argument simply can't be a reference to begin
with. It's usually more efficient to pass by reference when dealing with
function objects in particular and it also avoids the extra syntax of doing
it explicitly. So it's simply more natural to do it this way. Even when
you're not accumulating anything, developers won't have to think about the
fact that their local implementation is doing things inefficiently by
default. It really seems to put the onus on developers to be aware of what
their implementation is up to. That hardly seems appropriate. Other
implementations often work with references such as "binder2nd" (see the 2nd
arg of its constructor) but I know this causes problems. You can't pass
"mem_fun" to "bind2nd()" for instance if your member function takes a
reference argument. You'll end up with an (illegal) reference to a reference
in the 2nd constructor argument of "binder2nd" as just described. I brought
this to Stroustrup's attention via e-mail and he informed me that he himself
discovered the problem two years ago and a resolution was recently passed by
the committee to make references to references legal (they'll resolve to a
simple reference). You could simply argue though, well, why not just
eliminate the reference as in the "for_each" case. By rights I don't see why
it should be there anyway in that particular situation (if someone could
explain why I'd appreciate that too). I'm wondering however if any such
problem would apply to the "for_each" case (and others) by simply turning
the last argument into a reference which (on the surface anyway) seems more
appropriate. Any further comments?

"Howard Hinnant" <hinnant@antispam.twcny.rr.com> wrote in message
news:260620011940579817%hinnant@antispam.twcny.rr.com...
> In article <kk8_6.36849$Mf5.9580443@news3.rdc1.on.home.com>, Mark Kerns
> <nospam@nospam.com> wrote:
>
> | Even one of Stroustrup's own examples does it this way. Wouldn't it make
> | more sense however for the 3rd argument to be passed by reference
instead of
> | by value, assuming of course there's not some subtle mechanical reason
> | preventing it (since this arg must always properly resolve to something
that
> | can be executed, i.e., a function object or regular function pointer)? I
can
> | see versions taking both a "const" and "non-const" reference argument,
> | assuming "ambiguous" resolution problems won't occur (I'm not sure at
this
> | point). In any event, the way it stands, if you pass a function object
as
> | the 3rd argument then a copy of the object is passed instead of the
> | original. Therefore:
> |
> | A) Your function object *must* have a copy constructor (which it should
> | anyway if the default won't do)
> | B) More importantly, because a copy of your function object will be
executed
> | instead of the original, the original can't accumulate information on
each
> | iteration. In other words, if I do something like:
> |
> | CAccumulate Accumulate;
> | for_each(Iter1, Iter2, Accumulate);
> | int Total = Accumulate.GetTotal();
> |
> | This won't work because the "Accumulate" object is passed by value and
not
> | by reference. The same problem probably applies to other STL
implementations
> | I'm sure. Any comments and does the standard say anything about this?
>
> Actually passing by value makes a lot of sense.  Because you can easily
> specify what "by value" means via explicit template argument
> specification.  Unfortunately I believe the standard also will disallow>
the following
> (http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-active.html#92).
> However, in practice I suspect it will always work for for_each:
>
> #include <iostream>
> #include <algorithm>
>
> class CAccumulate
> {
> public:
>    CAccumulate() : sum_(0) {}
>    int GetTotal() const {return sum_;}
>    void operator()(int x) {sum_ += x;}
> private:
>    int sum_;
>
>    CAccumulate(const CAccumulate&);
>    CAccumulate& operator = (CAccumulate&);
> };
>
> int main()
> {
>    int ia[] = {1, 2, 3};
>    int* Iter1 = ia;
>    int* Iter2 = ia+3;
>    CAccumulate Accumulate;
>    std::for_each<int*, CAccumulate&>(Iter1, Iter2, Accumulate);
>    int Total = Accumulate.GetTotal();
>    std::cout << Total;
> }
>
> --
> Howard Hinnant
>
> ---
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]