Topic: Clarification about std::accumulate()


Author: gennaro_prota@yahoo.com (Gennaro Prota)
Date: Wed, 18 Oct 2006 21:48:07 GMT
Raw View
On Mon, 16 Oct 2006 12:14:26 CST, "James Kanze" <kanze.james@neuf.fr>
wrote:

>> >> I wonder, is the type of acc required to be T?
>
>> >Good question. I can't think of any other reasonable choice,
>> >but I agree it would be good if the standard said that
>> >explicitly. In fact, I don't even understand the need to
>> >introduce a new entity acc; as init is passed by value, you
>> >can just modify that, avoiding an unnecessary copy.
>
>> It is not passed by value when T is explicitly specified as a
>> reference type.
>
>But since it must be Assignable and Copiable, it can't be a
>reference.

Oops, I stopped reading too early. Now, what I notice about this
algorithm template is a) it's declared in a different header than
almost all others b) is carefully designed to be as inefficient as
possible (portably) c) doesn't generalize enough for my needs d)
disables a whole set of IMHO reasonable usages. Any others?

--
Gennaro Prota

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: gennaro_prota@yahoo.com (Gennaro Prota)
Date: Wed, 11 Oct 2006 17:02:35 GMT
Raw View
Hi,

from the C++03 description of std::accumulate():

  template <class InputIterator, class T>
  T accumulate(InputIterator first , InputIterator last , T init );

  Effects: Computes its result by initializing the accumulator acc
  with the initial value init [...]

I wonder, is the type of acc required to be T?

--
Gennaro Prota

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Wed, 11 Oct 2006 22:18:36 GMT
Raw View
Gennaro Prota ha scritto:
> Hi,
>
> from the C++03 description of std::accumulate():
>
>   template <class InputIterator, class T>
>   T accumulate(InputIterator first , InputIterator last , T init );
>
>   Effects: Computes its result by initializing the accumulator acc
>   with the initial value init [...]
>
> I wonder, is the type of acc required to be T?
>

Good question. I can't think of any other reasonable choice, but I agree
it would be good if the standard said that explicitly. In fact, I don't
even understand the need to introduce a new entity acc; as init is
passed by value, you can just modify that, avoiding an unnecessary copy.

Ganesh

PS: Same for inner_product.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "kanze" <kanze@gabi-soft.fr>
Date: Thu, 12 Oct 2006 10:41:26 CST
Raw View
Alberto Ganesh Barbati wrote:
> Gennaro Prota ha scritto:

> > from the C++03 description of std::accumulate():

> >   template <class InputIterator, class T>
> >   T accumulate(InputIterator first , InputIterator last , T init );

> >   Effects: Computes its result by initializing the accumulator acc
> >   with the initial value init [...]

> > I wonder, is the type of acc required to be T?

> Good question. I can't think of any other reasonable choice,

InputIterator::value_type?  (I don't really think so, but it
seems about the only other possible candidate in view.)

> but I agree it would be good if the standard said that
> explicitly.  In fact, I don't even understand the need to
> introduce a new entity acc; as init is passed by value, you
> can just modify that, avoiding an unnecessary copy.

I think an implementation can already do that, implicitly.
There's the "as if" rule, and the fact that one of the
implications in CopyConstructable is that it doesn't matter how
many copies or assignments are involved; if a type is
CopyConstructable, the program cannot tell.  (But does the
standard ever actually say that?)

An interesting thought just occurred to me, however.  There
doesn't seem to be any requirement that the return value of
binary_op be a T, or even something which converts to a T.  Nor
that it take its first parameter by value or even const
reference.  So I could define a binary_op whose first parameter
is a non-const reference, with a semantic comparable to that of
a += operator, and with a dummy return type, having overloaded
the assignment operator so that assignment from this dummy
return type is a no-op.  In order to get the performance of a +=
type operator for objects which are expensive to copy.

Or would this be bending the rules too much.  (I feel fairly
certain that this possibility wasn't created intentionally.)

--
James Kanze                                           GABI Software
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Thu, 12 Oct 2006 16:09:37 CST
Raw View
kanze wrote:
.
> An interesting thought just occurred to me, however.  There
> doesn't seem to be any requirement that the return value of
> binary_op be a T, or even something which converts to a T.  Nor
> that it take its first parameter by value or even const
> reference.  So I could define a binary_op whose first parameter
> is a non-const reference, with a semantic comparable to that of
> a += operator, and with a dummy return type, having overloaded
> the assignment operator so that assignment from this dummy
> return type is a no-op.  In order to get the performance of a +=
> type operator for objects which are expensive to copy.
>
> Or would this be bending the rules too much.  (I feel fairly
> certain that this possibility wasn't created intentionally.)

I think it was, in a sense, deliberate. I think the authors were
deliberately trying to avoid specifying anything more than the absolute
minimum that they had to specify to make it do what needed to be done.
I think this was done with the deliberate intent that each standard
library template could be used in more imaginative ways than the
obvious ones..

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Martin Bonner" <martinfrompi@yahoo.co.uk>
Date: Fri, 13 Oct 2006 11:12:23 CST
Raw View
kanze wrote:
> I think an implementation can already do that, implicitly.
> There's the "as if" rule, and the fact that one of the
> implications in CopyConstructable is that it doesn't matter how
> many copies or assignments are involved; if a type is
> CopyConstructable, the program cannot tell.  (But does the
> standard ever actually say that?)

I don't think that's right.  The implication of CopyConstructable is
that the copy is equivalent to the original (in some sense), but a copy
constructor is allowed to have side effects (eg do IO or increment a
counter).  That is why there is /explicit/ permission in the standard
to elide copies in certain circumstances, rather just relying on as-if.
 A program can tell if a copy has occured (but it ought not to care).

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "kanze" <kanze@gabi-soft.fr>
Date: Fri, 13 Oct 2006 11:49:11 CST
Raw View
kuyper@wizard.net wrote:
> kanze wrote:

> > An interesting thought just occurred to me, however.  There
> > doesn't seem to be any requirement that the return value of
> > binary_op be a T, or even something which converts to a T.  Nor
> > that it take its first parameter by value or even const
> > reference.  So I could define a binary_op whose first parameter
> > is a non-const reference, with a semantic comparable to that of
> > a += operator, and with a dummy return type, having overloaded
> > the assignment operator so that assignment from this dummy
> > return type is a no-op.  In order to get the performance of a +=
> > type operator for objects which are expensive to copy.

> > Or would this be bending the rules too much.  (I feel fairly
> > certain that this possibility wasn't created intentionally.)

> I think it was, in a sense, deliberate. I think the authors
> were deliberately trying to avoid specifying anything more
> than the absolute minimum that they had to specify to make it
> do what needed to be done.

Is it because they were specifying an absolute minimum, or
because they simply specified a specific implementation, rather
than trying to be explicit as to what is and is not required of
T and BinaryOperator here?  What is actually written looks like
it was simply extracted from an existing implementation.

> I think this was done with the deliberate intent that each
> standard library template could be used in more imaginative
> ways than the obvious ones..

I'm not sure.  In this case, the "specification" is a
specification as to exactly how the function is to be
implemented.  In many ways, it could be considered
"overspecification".  Taken literally, for example, it requires
that the local variable be named acc.  And that I can presumably
modify the effects by defining a macro acc before including the
header.  But I'm 100% sure that that wasn't the intent.

So is the fact that I can play games with "binary_op" and the
assignment operator intent, or an accidental side effect of the
fact that actual code was used to define requirements (which is,
IMHO, doing things backwards).

--
James Kanze                                           GABI Software
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Alberto Ganesh Barbati" <AlbertoBarbati@gmail.com>
Date: Fri, 13 Oct 2006 12:27:39 CST
Raw View
kanze ha scritto:

> Alberto Ganesh Barbati wrote:
> > Gennaro Prota ha scritto:
>
> > > from the C++03 description of std::accumulate():
>
> > >   template <class InputIterator, class T>
> > >   T accumulate(InputIterator first , InputIterator last , T init );
>
> > >   Effects: Computes its result by initializing the accumulator acc
> > >   with the initial value init [...]
>
> > > I wonder, is the type of acc required to be T?
>
> > Good question. I can't think of any other reasonable choice,
>
> InputIterator::value_type?  (I don't really think so, but it
> seems about the only other possible candidate in view.)
>

Another candidate might be typeof(init + *first), for some definition
of typeof. InputIterator:value_type can't be considered, IMHO, because
it would be error-prone in situations like this example:

std::vector<unsigned short> v;
//... fill v with a lot of values
unsigned long total = std::accumulate(v.begin(), v.end(), 0ul);

If an unsigned long is large enough to hold
std::numeric_limits<unsigned short>::max() * v.size() then I expect
this code to produce the correct result without overflowing. I think
that's a quite reasonable expectation, am I wrong? If acc were defined
as InputIterator:value_type, which is unsigned short, this would not be
the case.

I stand by my opinion that the standard should clarify that the type of
acc must be T. Whatever the original intent was, not specifying it
explicitly makes the algorithm difficult to use in situations like the
one described above.

Ganesh

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Gennaro Prota <gennaro_prota@yahoo.com>
Date: Fri, 13 Oct 2006 12:39:29 CST
Raw View
On Wed, 11 Oct 2006 22:18:36 GMT, AlbertoBarbati@libero.it (Alberto
Ganesh Barbati) wrote:

>> I wonder, is the type of acc required to be T?
>>
>
>Good question. I can't think of any other reasonable choice, but I agree
>it would be good if the standard said that explicitly. In fact, I don't
>even understand the need to introduce a new entity acc; as init is
>passed by value, you can just modify that, avoiding an unnecessary copy.

It is not passed by value when T is explicitly specified as a
reference type. But even in that case your statement remains valid
that init can be used directly.

--
Gennaro Prota

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Fri, 13 Oct 2006 12:39:19 CST
Raw View
kanze wrote:
> kuyper@wizard.net wrote:
> > kanze wrote:
>
> > > An interesting thought just occurred to me, however.  There
> > > doesn't seem to be any requirement that the return value of
> > > binary_op be a T, or even something which converts to a T.  Nor
> > > that it take its first parameter by value or even const
> > > reference.  So I could define a binary_op whose first parameter
> > > is a non-const reference, with a semantic comparable to that of
> > > a += operator, and with a dummy return type, having overloaded
> > > the assignment operator so that assignment from this dummy
> > > return type is a no-op.  In order to get the performance of a +=
> > > type operator for objects which are expensive to copy.
>
> > > Or would this be bending the rules too much.  (I feel fairly
> > > certain that this possibility wasn't created intentionally.)
>
> > I think it was, in a sense, deliberate. I think the authors
> > were deliberately trying to avoid specifying anything more
> > than the absolute minimum that they had to specify to make it
> > do what needed to be done.
>
> Is it because they were specifying an absolute minimum, or
> because they simply specified a specific implementation, rather
> than trying to be explicit as to what is and is not required of
> T and BinaryOperator here?  What is actually written looks like
> it was simply extracted from an existing implementation.
>
> > I think this was done with the deliberate intent that each
> > standard library template could be used in more imaginative
> > ways than the obvious ones..
>
> I'm not sure.  In this case, the "specification" is a
> specification as to exactly how the function is to be
> implemented.  In many ways, it could be considered
> "overspecification".  Taken literally, for example, it requires
> that the local variable be named acc.  And that I can presumably
> modify the effects by defining a macro acc before including the
> header.  But I'm 100% sure that that wasn't the intent.

I agree that it wasn't the intent. I disagree with your conclussion
about defining such a macro. There's no guarantee that the definition
of the function is in the standard header, which it would have to be to
be susceptible to change in that fashion. Except, of course, for
implementions which haven't implemented 'export' yet.

I think there's a statement in the section that describes the general
rules for using standard library templates, that explicitly sets limits
on what we should interpret from behavior defined by example code.
However, my copy of the standard isn't accessible right now, so I can't
search for it right now.

> So is the fact that I can play games with "binary_op" and the
> assignment operator intent, or an accidental side effect of the
> fact that actual code was used to define requirements (which is,
> IMHO, doing things backwards).

Here, I disagree. I think the behavior was defined in terms of a code
sample, with the deliberate intent of allowing users to know which
operator overloads and implicit conversions would be invoked by the
function, if instantiated with a UDT for which such overloads and
conversions have been defined. I think implementators are not required
to use exactly the provided code, but must use code that invokes the
same operator overloads as if they had. After all, for most standard
library templates, not using applicable operator overloads would be
pretty hard to arrange, at least in the general case.

Of course, the easiest way to find out what the actual intent was,
would be to ask the author(s). The official way to ask would be to file
a Defect report, but I'm not sure this question requires that level of
formality (I don't think there's a defect, after all). Is there a less
formal way to deliver this question to the right person?

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: gennaro_prota@yahoo.com (Gennaro Prota)
Date: Fri, 13 Oct 2006 17:48:59 GMT
Raw View
On Fri, 13 Oct 2006 11:49:11 CST, "kanze" <kanze@gabi-soft.fr> wrote:

>I'm not sure.  In this case, the "specification" is a
>specification as to exactly how the function is to be
>implemented.  In many ways, it could be considered
>"overspecification".

<digression>

The stream extractor of std::bitset immediately comes to mind :-)
Incidentally I had pointed out that there's no reason to use a string
there and the libstdc++ guys had actually removed it; but they removed
the removal (;-)), afterwards, and I have never known why.

Similarly several TR1 parts seem more or less copied from/modeled upon
the boost docs, and enable_if is mentioned in a couple of notes even
though it's not specified anywhere in the standard.

</digression>

--
Gennaro Prota

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Mon, 16 Oct 2006 11:32:03 CST
Raw View
kuyper@wizard.net wrote:
.
> I think there's a statement in the section that describes the general
> rules for using standard library templates, that explicitly sets limits
> on what we should interpret from behavior defined by example code.
> However, my copy of the standard isn't accessible right now, so I can't
> search for it right now

It does exist: 17.3.1.2p6; but it's not quite as specific as I'd hoped
it was: "In some cases the semantic requirements are presented as C++
code. Such code is intended as a specification of equivalence of a
construct to another construct, not necessarily as the way the
construct must be implemented."

I would argue that the operator overloads and implicit conversions
implied by such code are part of the semantics.  As such, they are
required to happen as indicated by the code which is used to describe
the required behavior. However, the names of any variables used in
expressing that requirement are not part of the semantics, and the use
of different names is therefor allowed.

However, I can't argue that this is as clearly the case as I'd like it
to be.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Gennaro Prota <gennaro_prota@yahoo.com>
Date: Mon, 16 Oct 2006 11:49:38 CST
Raw View
On Fri, 13 Oct 2006 12:39:19 CST, kuyper@wizard.net wrote:

>Of course, the easiest way to find out what the actual intent was,
>would be to ask the author(s). The official way to ask would be to file
>a Defect report, but I'm not sure this question requires that level of
>formality (I don't think there's a defect, after all). Is there a less
>formal way to deliver this question to the right person?

No answer. Let's decide who is going to be 'it' for the DR :-)

--
Gennaro Prota

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Mon, 16 Oct 2006 17:10:43 GMT
Raw View
Gennaro Prota ha scritto:
> On Wed, 11 Oct 2006 22:18:36 GMT, AlbertoBarbati@libero.it (Alberto
> Ganesh Barbati) wrote:
>
>>> I wonder, is the type of acc required to be T?
>>>
>> Good question. I can't think of any other reasonable choice, but I agree
>> it would be good if the standard said that explicitly. In fact, I don't
>> even understand the need to introduce a new entity acc; as init is
>> passed by value, you can just modify that, avoiding an unnecessary copy.
>
> It is not passed by value when T is explicitly specified as a
> reference type. But even in that case your statement remains valid
> that init can be used directly.

Ouch! So an implementation that would like to avoid the unnecessary copy
in the general case should be careful to provide a different
implementation in case T is (explicitly specified to be) a reference or
const type, because:

1) if T const or const-reference, it clearly can't be modified

2) if T is a non-const reference, then calling the algorithm would have
a side-effect (would modify init in the caller context) that shouldn't occur

I wonder how many implementations do that... ;-)

Ganesh

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "James Kanze" <kanze.james@neuf.fr>
Date: Mon, 16 Oct 2006 12:14:26 CST
Raw View
Gennaro Prota wrote:
> On Wed, 11 Oct 2006 22:18:36 GMT, AlbertoBarbati@libero.it (Alberto
> Ganesh Barbati) wrote:

> >> I wonder, is the type of acc required to be T?

> >Good question. I can't think of any other reasonable choice,
> >but I agree it would be good if the standard said that
> >explicitly. In fact, I don't even understand the need to
> >introduce a new entity acc; as init is passed by value, you
> >can just modify that, avoiding an unnecessary copy.

> It is not passed by value when T is explicitly specified as a
> reference type.

But since it must be Assignable and Copiable, it can't be a
reference.

Interestingly enough, I can't find where it requires
BinaryOperator to be Copiable or Assignable.  The same remark
holds for the operators to transform and Generator in generate.
For that matter, this requirement doesn't seem to be mentioned
for Predicate nor for BinaryPredicate in the general
requirements.  Is there some global statement somewhere else?
I'm sure that this is the intent, given the call by value
semantics.  (Perhaps a general statement is in order, to the
effect that anytime a template parameter type is passed by
value, it must be Copiable and Assignable, unless otherwise
stated.)

--
James Kanze (Gabi Software)              email: kanze.james@neuf.fr
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "James Kanze" <kanze.james@neuf.fr>
Date: Mon, 16 Oct 2006 12:14:40 CST
Raw View
kanze wrote:

> An interesting thought just occurred to me, however.  There
> doesn't seem to be any requirement that the return value of
> binary_op be a T, or even something which converts to a T.
> Nor that it take its first parameter by value or even const
> reference.  So I could define a binary_op whose first
> parameter is a non-const reference, with a semantic comparable
> to that of a += operator, and with a dummy return type, having
> overloaded the assignment operator so that assignment from
> this dummy return type is a no-op.  In order to get the
> performance of a += type operator for objects which are
> expensive to copy.

> Or would this be bending the rules too much.  (I feel fairly
> certain that this possibility wasn't created intentionally.)

FWIW: I just added this to my digest hasher templates last
Friday.  Using it speeded up MD5 hashing by a factor of 4, and
SHA-1 by a factor of 8, compared to using the standard operator+
(which copies the hash accumulator all over the place).  In
fact, with it, there's no significant difference between using
accumulate and using the templated member function
append(FwdIter, FwdIter).

Now if only I were sure that it were legal:-).

--
James Kanze (Gabi Software)              email: kanze.james@neuf.fr
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "James Kanze" <kanze.james@neuf.fr>
Date: Mon, 16 Oct 2006 12:14:56 CST
Raw View
Martin Bonner wrote:
> kanze wrote:

> > I think an implementation can already do that, implicitly.
> > There's the "as if" rule, and the fact that one of the
> > implications in CopyConstructable is that it doesn't matter
> > how many copies or assignments are involved; if a type is
> > CopyConstructable, the program cannot tell.  (But does the
> > standard ever actually say that?)

> I don't think that's right.  The implication of CopyConstructable is
> that the copy is equivalent to the original (in some sense),

And the implication of that is that the implementation is free
to copy, when and where it pleases.

> but a copy constructor is allowed to have side effects (eg do
> IO or increment a counter).

Yes, but a conforming program cannot count on the exact number
of copies which are made.  So in practice, any side effects must
be without an effect on the desired observable behavior of the
program.  (I agree that debugging statements which include
output are permitted, but if the implementation makes a few
copies more or less, I don't think that the user has a right to
complain.)

> That is why there is /explicit/ permission in the standard to
> elide copies in certain circumstances, rather just relying on
> as-if.

That's a different case, although with similar motivation.  In
this case, I don't think it requires any real extra language,
because the definition of CopyConstructable is vague enough that
it is already implicitly there.

>  A program can tell if a copy has occured (but it ought not to
>  care).

Yes.  That's probably a better formulation, although I'd replace
"ought not" with "must not".

--
James Kanze (Gabi Software)              email: kanze.james@neuf.fr
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "James Kanze" <kanze.james@neuf.fr>
Date: Mon, 16 Oct 2006 12:29:01 CST
Raw View
Alberto Ganesh Barbati wrote:
> kanze ha scritto:

> > Alberto Ganesh Barbati wrote:
> > > Gennaro Prota ha scritto:

> > > > from the C++03 description of std::accumulate():

> > > >   template <class InputIterator, class T>
> > > >   T accumulate(InputIterator first , InputIterator last , T init );

> > > >   Effects: Computes its result by initializing the accumulator acc
> > > >   with the initial value init [...]

> > > > I wonder, is the type of acc required to be T?

> > > Good question. I can't think of any other reasonable choice,

> > InputIterator::value_type?  (I don't really think so, but it
> > seems about the only other possible candidate in view.)

> Another candidate might be typeof(init + *first), for some
> definition of typeof. InputIterator:value_type can't be
> considered, IMHO, because it would be error-prone in
> situations like this example:

> std::vector<unsigned short> v;
> //... fill v with a lot of values
> unsigned long total = std::accumulate(v.begin(), v.end(), 0ul);

> If an unsigned long is large enough to hold
> std::numeric_limits<unsigned short>::max() * v.size() then I
> expect this code to produce the correct result without
> overflowing. I think that's a quite reasonable expectation, am
> I wrong?

I don't think so, but I'm not sure whether I'm reasoning from a
standards point of view, or a quality of implementation point of
veiw.  As I said, I don't really consider it a valid candidate,
but it was the only one I could think of.

> If acc were defined as InputIterator:value_type, which is
> unsigned short, this would not be the case.

> I stand by my opinion that the standard should clarify that
> the type of acc must be T. Whatever the original intent was,
> not specifying it explicitly makes the algorithm difficult to
> use in situations like the one described above.

I agree.

I'd also like a more complete specification concerning the
constraints of BinaryOperator.  I presume Assignable and
CopyConstructable, and of course, the expression binary_op( T,
InputIterator::value_type ) must be legal, and return something
which is assignable to or convertable to a T.  And am I
guaranteed that the first argument is a non-const lvalue, so
that it can bind to a non-const reference, or am I required to
pass by const reference or value?  Could, for example, an
implementation unroll the loop, and do something like:

    acc = binary_op( binary_op( acc, i[0] ), i[1] ) ;
    i += 2 ;

if it determined that the iterator was random access?  (My
gut feeling is that the original intent would have been to allow
something like this.  It is definitly illegal if you take the
wording of the current standard at face value, because of the
way the effects are described.)

--
James Kanze (Gabi Software)              email: kanze.james@neuf.fr
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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.comeaucomputing.com/csc/faq.html                      ]