C++11 SCARYイテレータ

C++11から、SCARYイテレータ(怖いイテレータ)という規定が入りました。

SCARYというのは「Seemingly erroneous (Constrained by conflicting generic parameters), but Actually work with the Right implementation (unconstrained bY the conflict due to minimized dependencies).」の略で、「(競合するテンプレートパラメータによって制約されるから)一見間違ったコードに見えるけど、(依存関係の最小化によって)実際には正しく動く」という意味です。

こじつけ感満載の略語ですが、これは以下のようなものです。

vector<int> v1;
vector<int, MyAllocator<int>> v2;

decltype(v1)::iterator it = v1.begin();
it = v2.begin(); // OK

つまり、標準コンテナのイテレータの依存関係を最小化し、異なるアロケータのイテレータ同士でも代入可能にしよう、というものです。イテレータはアロケータを使わないので、コンパイルを通してしまっていいだろう、と。

この依存関係の最小化はアロケータのみならず、setmapの比較演算子、unordered連想コンテナのハッシュ関数も対象になります。

Clangは3.1から、VCは2012(11.0)からSCARYイテレータをサポートしています。GCCは4.8時点でまだ対応していません。Boost.Containerは1.55.0からこれをサポートしています。以下、実際に動くコード:

#include <vector>

template <class T>
struct MyAllocator {
    using value_type = T;

    static T* allocate(std::size_t n)
    {
        return new T[n];
    }

    static void deallocate(T* pointer, std::size_t n)
    {
        static_cast<void>(n);
        delete[] pointer;
    }
};

int main()
{
    std::vector<int> v1;
    std::vector<int, MyAllocator<int>> v2;

    decltype(v1)::iterator it = v1.begin();
    it = v2.begin();
}

参照