For example uninitialized_copy
is defined in the standard as:
Effects:
for (; first != last; ++result, ++first) ::new (static_cast<void*>(&*result)) typename iterator_traits<ForwardIterator>::value_type(*first);
If understood literally, this is a requirement to call operator ,(ForwardIterator, InputIterator)
. And in fact this code prints Hello world!
ten times:
#include <memory>
#include <iterator>
#include <iostream>
using namespace std;
namespace N {
struct X : iterator<forward_iterator_tag, int> {
pointer _p;
X(pointer p) : _p(p) {}
X& operator++() { ++_p; return *this; }
X operator++(int) { X r(*this); ++_p; return r; }
reference operator*() const { return *_p; }
pointer operator->() const { return _p; }
};
bool operator==(X a, X b) { return a._p == b._p; }
bool operator!=(X a, X b) { return !(a == b); }
void operator,(X a, X b) { cout << "Hello world!\n"; }
}
int a[10], b[10];
int main()
{
using N::X;
uninitialized_copy(X(a), X(a+10), X(b));
}
However, for most other algorithms the standard gives the description in prose. E.g. for copy
there's no requirement for operator ,
to be called. But if I change
uninitialized_copy(X(a), X(a+10), X(b));
in the above code to
copy(X(a), X(a+10), X(b));
then Hello world!
is still printed ten times. The said results are observable in both, VS2005 and GCC 4.3.4. However, if I write
mismatch(X(a), X(a+10), X(b));
instead, then VS2005 prints Hello world!
ten times but GCC does not.
Unfortunately I couldn't find where the standard prohibits operator,
overloading for iterator types. On the contrary, it prohibits the implementations to do calls as above [global.functions]:
Unless otherwise specified, global and non-member functions in the standard library shall not use functions from another namespace which are found through argument-dependent name lookup (3.4.2).
So who of the four parties is wrong: MSVC, GCC, ISO or me? (Choose one)
Nice catch. I think in my humble opinion that the ISO committee's intention was that §3.4.2 should be followed. The suggested semantics of uninitialized_copy
is wrongly interpreted as if requiring the comma to be called. And implementations should not be using it (I'd report a bug to gcc btw).