Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

std::accum w/ unary op

7 views
Skip to first unread message

tf

unread,
Aug 28, 2010, 4:40:51 PM8/28/10
to
I just had quite a confusing bout with my compiler, until I realized
that the following wasn't part of the standard:

namespace nonstd {
// an accumulate which follows the standard accumulate, except
// instead of:
// result = result + *i
// at each iteration, it performs:
// result = result + f(*i)
// i.e. it applies a unary op to the item iterated over.
template<class InputIter, typename T, class UnaryFunc>
T accumulate(InputIter first, InputIter last, T init,
UnaryFunc uop)
{
T rv = init;
for(; first != last; ++first) {
rv = rv + uop(*first);
}
return rv;
}
}

It seems like this would come up a lot whilst calling member functions:

struct X { int f() { return 1; }
int a = nonstd::accumulate(Xcontainer.begin(), Xcontainer.end(), 0,
std::tr1::mem_fn(&X::f));
...

Which to me is considerably more convenient/clear than emulating it w/ a
binop. Admittedly the binop allows one to do any arbitrary reduce
operation... but I find little need for such an operation in practice.

Everyone else just implementing this and sucking up the complaint?

-tom

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Daniel Krügler

unread,
Aug 28, 2010, 5:58:36 PM8/28/10
to

I never needed to implement this, but I agree that the
functionality looks both useful and fundamental. For
consistency reasons it would be appropriate to add
this for adjacent_difference, partial_sum, and inner_product
as well.

The reason why I never missed it was that I always used
boost::transform_iterator in such use cases. IMO, this is
also a very fundamental iterator facade that could be
standardized.

HTH & Greetings from Bremen,

Daniel Krügler

AJG

unread,
Aug 30, 2010, 12:35:33 AM8/30/10
to

Yeah, I believe I've had to implement something like that at least a
couple of times. It'd be useful to have as part of the STL.

David Krauss

unread,
Sep 13, 2010, 6:58:23 PM9/13/10
to
On Aug 28, 3:40=A0pm, tf <t...@sci.utah.edu> wrote:
> I just had quite a confusing bout with my compiler, until I realized
> that the following wasn't part of the standard:
>
> =A0 =A0namespace nonstd {
> =A0 =A0 =A0// an accumulate which follows the standard accumulate, except
> =A0 =A0 =A0// instead of:
> =A0 =A0 =A0// =A0 =A0result = result + *i
> =A0 =A0 =A0// at each iteration, it performs:
> =A0 =A0 =A0// =A0 =A0result = result + f(*i)
> =A0 =A0 =A0// i.e. it applies a unary op to the item iterated over.
> =A0 =A0 =A0template<class InputIter, typename T, class UnaryFunc>
> =A0 =A0 =A0T accumulate(InputIter first, InputIter last, T init,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 UnaryFunc uop)

If this were in std::, the implementation would have to discriminate
unary vs binary function arguments in the fourth parameter, which
would make it much more complicated, if feasible at all.

On the other hand, it's only useful if you're already passing a custom
unary operation. In that case, why not add an extra argument and a
plus sign and make it a binary accumulation operation?

I agree 100% that transform_iterator should be in the standard and I'm
very disappointed it isn't. Yes, it cannot elegantly satisfy Iterator
requirements because either operator-> is missing or the current value
is cached, and it's read-only even if it is random-access. But that's
a problem with the Iterator requirements, not with transform_iterator,
as evidenced by the fact it works just fine with the STL algorithms.

tf

unread,
Sep 25, 2010, 2:45:53 AM9/25/10
to
David Krauss wrote:
> On Aug 28, 3:40=A0pm, tf <t...@sci.utah.edu> wrote:
>> I just had quite a confusing bout with my compiler, until I realized
>> that the following wasn't part of the standard:
>>
>> =A0 =A0namespace nonstd {
>> =A0 =A0 =A0// an accumulate which follows the standard accumulate, except
>> =A0 =A0 =A0// instead of:
>> =A0 =A0 =A0// =A0 =A0result = result + *i
>> =A0 =A0 =A0// at each iteration, it performs:
>> =A0 =A0 =A0// =A0 =A0result = result + f(*i)
>> =A0 =A0 =A0// i.e. it applies a unary op to the item iterated over.
>> =A0 =A0 =A0template<class InputIter, typename T, class UnaryFunc>
>> =A0 =A0 =A0T accumulate(InputIter first, InputIter last, T init,
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 UnaryFunc uop)

[side note -- you replaced all the spaces here with "=A0 ". If I'm
sending ascii but my headers say my messages are UTF or something,
please inform me privately. Otherwise, please fix your client.]

{ It may be an issue with our new moderation software, sorry. -mod/sk }

> If this were in std::, the implementation would have to discriminate
> unary vs binary function arguments in the fourth parameter, which
> would make it much more complicated, if feasible at all.

Ahh, I did not think of that. Still, perhaps this is possible w/ some
use of boost::is_function or boost::is_member_function?

http://www.boost.org/doc/libs/1_44_0/libs/type_traits/doc/html/boost_typetraits/reference/is_function.html

> On the other hand, it's only useful if you're already passing a custom
> unary operation. In that case, why not add an extra argument and a
> plus sign and make it a binary accumulation operation?

You have not reproduced enough of my post. I'll repeat the example use
case I gave:

int a = nonstd::accumulate(Xcontainer.begin(), Xcontainer.end(), 0,
std::tr1::mem_fn(&X::f));

Note I'm calling a member function of X. It is conceivable that I am
not able to modify X.

Yes, I can always define my own custom functor which takes an X and a
nothing-argument, but the point of the post was that the current
interface is cumbersome for what I commonly do (actually, the binop w/
nothing-argument was the approach I used until the day I made the post).

[snip -- transform_iterator]

No experience w/ this myself, but perhaps I should change that...

-tom

0 new messages