web-dev-qa-db-ja.com

const_iteratorとイテレータの比較は明確に定義されていますか?

次のコードについて考えてみます。

_#include <vector>
#include <iostream>

int main()
{
    std::vector<int> vec{1,2,3,5};
    for(auto it=vec.cbegin();it!=vec.cend();++it)
    {
        std::cout << *it;
        // A typo: end instead of cend
        if(next(it)!=vec.end()) std::cout << ",";
    }
    std::cout << "\n";
}
_

ここでタイプミスを紹介しました。比較では、vec.end()ではなくvec.cend()と呼びました。これは、gcc5.2で意図したとおりに機能するようです。しかし、それは実際には規格に従って明確に定義されていますか? iteratorと_const_iterator_を安全に比較できますか?

30
Ruslan

驚いたことに、C++ 98とC++ 11は、iteratorconst_iteratorと比較できるとは言っていませんでした。これにより、 LWG問題179 および LWG問題226 になります。現在C++ 14では、これは§23.2.1[container.requirements.general] p7によって明示的に許可されています。

式で

i == j
i != j
i < j
i <= j
i >= j
i > j
i - j

ここで、ijは、コンテナのiteratorタイプのオブジェクトを示し、いずれかまたは両方を、同じ要素を参照するコンテナのconst_iteratorタイプのオブジェクトに置き換えることができます。セマンティクスに変更はありません。

31
cpplearner

C++ 11標準の表96のセクション23.2.1では、任意のコンテナタイプXstd::vectorを含む)のa.cend()操作的意味論を次のように定義しています。

const_cast<X const &>(a).end()

したがって、この定義ではcend()end()と同じコンテナ内の要素/位置を参照し、X::iteratorX::const_iterator(a同じ表で指定されている要件(*))。

(同じ表で定義されているのと同じ理由で、begin()cbegin()の答えも「はい」です。)


(*) 他の回答へのコメントで、兌換性は必ずしも比較操作i1==i2が常に機能することを意味するわけではないことが指摘されています。 operator==()がイテレータ型のメンバー関数である場合、暗黙的な変換は、左側の引数ではなく、右側の引数に対してのみ受け入れられます。 24.2.5/6状態(フォワードイテレータaおよびbについて):

abの両方が逆参照可能である場合、a == b*aが同じオブジェクトにバインドされている場合に限り、*b

イテレータend()cend()は参照解除できませんが、上記のステートメントは、aがconstであっても、比較が可能なようにoperator==()を定義する必要があることを意味します。 -iteratorとbはそうではなく、その逆も同様です。24.2.5は、constバージョンとnon-constバージョンの両方を含む一般的なフォワードイテレーターに関するものだからです。 24.2.5/1から。これが、兌換性を指す表96の文言も、比較可能性を意味すると確信している理由です。しかし、cpplearner @の後の回答で説明されているように、これはC++ 14でのみ明示的に明確にされています。

9
jogojapan

§23.2.1、表96を参照してください。

X::iterator

[...]

フォワードイテレータの要件を満たすイテレータカテゴリ。

X::const_iteratorに変換可能

だから、はい、それは明確に定義されています。

9
Christian Hackl