27

たとえばuninitialized_copy、標準では次のように定義されています。

効果:

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

文字通り理解されている場合、これはを呼び出すための要件ですoperator ,(ForwardIterator, InputIterator)。実際、このコードはHello world!10回出力されます。

#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!10回印刷されます。上記の結果は、VS2005とGCC4.3.4の両方で観察できます。しかし、私が書くと

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

代わりに、VS2005はHello world!10回印刷しますが、GCCは印刷しません。

残念ながら、標準operator,でイテレータ型のオーバーロードが禁止されている場所が見つかりませんでした。それどころか、実装が上記のように呼び出しを行うことを禁止しています[global.functions]:

特に指定がない限り、標準ライブラリのグローバル関数と非メンバー関数は、引数依存の名前ルックアップ(3.4.2)で見つかった別の名前空間の関数を使用してはなりません。

では、MSVC、GCC、ISO、または私という4つのパーティのうち誰が間違っているのでしょうか。(1つ選択してください)

4

1 に答える 1

4

ナイスキャッチ。私の謙虚な意見では、ISO委員会の意図は§3.4.2に従うべきであると思います。の提案されたセマンティクスはuninitialized_copy、コンマを呼び出す必要があるかのように誤って解釈されます。そして、実装はそれを使用すべきではありません(gcc btwにバグを報告します)。

于 2012-01-03T23:32:34.013 に答える