自前のインサートイテレータ

BCC582 (C++Builder 2006) では問題なかった下記のような自前のインサートイテレータがあります。

template <class X>
class MyInsertIterator {
public:
    MyInsertIterator(X& x) : x_(&x) {};
    MyInsertIterator& operator =  (const Foo& v) { x_->Add(v); return *this; }
    MyInsertIterator& operator *  ()    { return *this; }
    MyInsertIterator& operator ++ ()    { return *this; }
    MyInsertIterator& operator ++ (int) { return *this; }
protected:
    X* x_;
};

template <class X>
inline MyInsertIterator<X> MyInserter(X& x)
{
    return MyInsertIterator<X>(x);
}

これを std::copy で使っているのですが、VC141 (Visual Studio 2017 の Visual C++) でデバッグ用ビルドすると warning C4996 と error C2794 が報告されます。

まず error C2794 対策、

エラーメッセージは

'iterator_category': 'std::iterator_traits<_Iter>' の基底クラスの直接的または間接的なメンバーではありません。

ですが、イテレータの特性が取得できないみたいです。そこで MyInsertIterator クラス定義内に以下を追加します。

public:
    using iterator_category = std::output_iterator_tag;
    using difference_type = void;
    using value_type = void;
    using pointer = void;
    using reference = void;
    using container_type = X;

つづいて warning C4996 対策、

警告メッセージは

'std::copy::_Unchecked_iterators::_Deprecate': Call to 'std::copy' with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'

ということで、マクロ _SCL_SECURE_NO_WARNINGS を定義するとか、pragma で warning C4996 を無効にしてしまう方法もありますが、他への影響を最小限にするため、MyInsertIterator クラス定義の後に以下を追加してイテレータを checked の扱いにしてしまいます。

template<class _Container>
struct std::_Is_checked_helper<MyInsertIterator<_Container> > : public std::true_type {};

最後に、全体のコード例を載せて起きます。

長くなりそうだったので X::Add(Foo) の代わりに X::push_back(int) になってます。

#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>

using namespace std;

template <class X>
class MyInsertIterator {
public:
    using iterator_category = output_iterator_tag;
    using difference_type = void;
    using value_type = void;
    using pointer = void;
    using reference = void;
    using container_type = X;
    MyInsertIterator(X& x) : x_(&x) {};
    MyInsertIterator& operator =  (const typename X::value_type& v) { x_->push_back(v); return *this; }
    MyInsertIterator& operator *  ()    { return *this; }
    MyInsertIterator& operator ++ ()    { return *this; }
    MyInsertIterator& operator ++ (int) { return *this; }
protected:
    X* x_;
};

template <class X>
struct _Is_checked_helper<MyInsertIterator<X> > : public true_type {};

template <class X>
inline MyInsertIterator<X> MyInserter(X& x)
{
    return MyInsertIterator<X>(x);
}

int main()
{
    vector<int> v = { 2, 3, 5, 7, 11, 13 };
    vector<int> w;
    copy(v.begin(), v.end(), MyInserter(w));
    cout << "w:";
    for (auto& i : v) {
        cout << ' ' << i;
    }
    cout << endl;
}