invalid iterator同士の比較

諸事情でブログ名変えました。

libstdc++とSTLportでは普通に通る下のようなコードが、VC++ (dinkumware) (2008-12-18 04:50追記: VC++の_SCL_SECURE系のチェックによるものなのでdinkumwareはあんまり関係ない) では動かなくて困っていた。operator==()で落ちる。

#include <typeinfo>
#include <iterator>
#include <iostream>
#include <vector>
#include <map>

template<typename Titer_>
struct get_iterator_category {
    typedef typename Titer_::iterator_category type;
};

// STLportでは、std::vector<>::iteratorはただのポインタ
template<typename Tany_>
struct get_iterator_category<Tany_*> {
    typedef std::random_access_iterator_tag type;
};


template<typename Titer_>
void iterator_test()
{
    std::cout << typeid(Titer_).name() << std::endl;
    std::cout << typeid(typename get_iterator_category<Titer_>::type).name() << std::endl;
    std::cout << (Titer_() == Titer_() ? "yes!": "hmm..") << std::endl;
}

int main(int, char**)
{
    iterator_test<std::vector<int>::const_iterator>();
    iterator_test<std::map<int, int>::const_iterator>();
    return 0;
}

で、まあそもそもこのような比較はありなのかってことでn2461のworking draft読んでみた。

結論から言うと、これに関する仕様は非常に曖昧なので使うなって言ってしまっていいような気がする。

この曖昧さは、C++イテレータの仕様 (24.1) のpast-the-end valuesの定義に続く次の説明

Iterators can also have singular values that are not associated with any container.

これに由来している。

  1. イテレータはどのコンテナとも関連づけられていないような特異値も持つことができる。(→past-the-end valuesもまたsingularである)
  2. イテレータは、また、どのコンテナとも関連づけられていないという、特異値も持つことができる。(→past-the-end valuesとsingular valuesは別物である)

どちらに解釈するかでかなり意味合いが異なるのだ。なぜこれが問題になるかというと、その後で、

と説明されているからで、1. だとすると、コンテナのすべての要素を含むようなrangeの終端はpast-the-endとなるので、仕様上矛盾が生じる。かといって 2. とも言い切れないのは、口語と違ってthatは通常restrictiveな文脈で使われるからだ。これを信じるとすると、特異なイテレータに関する制約についての仕様が誤っていると考えることもできる。