Должна ли реализация защищать себя от перегрузки запятыми? - PullRequest
26 голосов
/ 04 января 2012

Например, uninitialized_copy определяется в стандарте как:

Эффекты:

for (; first != last; ++result, ++first)
  ::new (static_cast<void*>(&*result))
    typename iterator_traits<ForwardIterator>::value_type(*first);

Если понимать буквально, этотребование позвонить operator ,(ForwardIterator, InputIterator).И на самом деле этот код печатает Hello world! десять раз:

#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));
}

Однако для большинства других алгоритмов стандарт дает описание в прозе.Например, для copy нет необходимости вызывать оператора ,.Но если я изменю

    uninitialized_copy(X(a), X(a+10), X(b));

в приведенном выше коде на

    copy(X(a), X(a+10), X(b));

, то Hello world! будет , все равно напечатано десять раз .Указанные результаты наблюдаются как в VS2005, так и в GCC 4.3.4.Однако, если я вместо этого пишу

    mismatch(X(a), X(a+10), X(b));

, VS2005 печатает Hello world! десять раз, а GCC - нет.

К сожалению, я не смог найти, где стандарт запрещает перегрузку operator, длятипы итераторов.Напротив, он запрещает реализациям выполнять вызовы, как указано выше [global.functions]:

Если не указано иное, глобальные и не являющиеся членами функции в стандартной библиотеке не должны использовать функции из другого пространства имен, которыенаходятся в аргументно-зависимом поиске имени (3.4.2).

Итак, кто из четырех сторон ошибается: MSVC, GCC, ISO или я?(Выберите один)

1 Ответ

3 голосов
/ 04 января 2012

Хороший улов. Я считаю, что, по моему скромному мнению, комитет ИСО намеревался следовать §3.4.2. Предлагаемая семантика uninitialized_copy неверно интерпретируется, как если бы она требовала вызова запятой. И реализации не должны его использовать (я бы сообщил об ошибке в gcc btw).

...