web-dev-qa-db-ja.com

廃止予定のstd :: iteratorの準備

3月21日st 標準化委員会は、 std::iterator の非推奨を承認するために投票しました P0174 で提案:

Void引数の長いシーケンスは、クラス定義自体で予想されるtypedefsを単に提供するよりもはるかに明確ではありません。これは、 c ++ 14

c ++ 17 からの継承std::iteratorからの継承は、イテレータの定型的な実装から退屈なものを削除することが推奨されていました。ただし、非推奨には次のいずれかが必要です。

  1. イテレータのボイラープレートには、必要なすべてのtypedefsを含める必要があります
  2. イテレータで動作するアルゴリズムは、イテレータに依存して型を宣言するのではなく、autoを使用する必要があります
  3. Loki Astariが示唆したstd::iterator_traits は、std::iteratorから継承せずに動作するように更新される可能性がある

c ++ 17 互換性を念頭に置いてカスタムイテレータを設計しているため、これらのオプションのどれを期待すべきかを誰かに教えてもらえますか?

57
Jonathan Mee

議論された代替案は明確ですが、コード例が必要だと感じています。

言語の代替がなく、ブーストまたはイテレータ基本クラスの独自バージョンに依存しない場合、std::iteratorを使用する次のコードは、その下のコードに修正されます。

std::iteratorを使用

template<long FROM, long TO>
class Range {
public:
    // member typedefs provided through inheriting from std::iterator
    class iterator: public std::iterator<
                        std::forward_iterator_tag, // iterator_category
                        long,                      // value_type
                        long,                      // difference_type
                        const long*,               // pointer
                        const long&                // reference
                                      >{
        long num = FROM;
    public:
        iterator(long _num = 0) : num(_num) {}
        iterator& operator++() {num = TO >= FROM ? num + 1: num - 1; return *this;}
        iterator operator++(int) {iterator retval = *this; ++(*this); return retval;}
        bool operator==(iterator other) const {return num == other.num;}
        bool operator!=(iterator other) const {return !(*this == other);}
        long operator*() {return num;}
    };
    iterator begin() {return FROM;}
    iterator end() {return TO >= FROM? TO+1 : TO-1;}
};

http://en.cppreference.com/w/cpp/iterator/iterator からのコード。元の著者の許可を得て)。

std::iteratorなし

template<long FROM, long TO>
class Range {
public:
    class iterator {
        long num = FROM;
    public:
        iterator(long _num = 0) : num(_num) {}
        iterator& operator++() {num = TO >= FROM ? num + 1: num - 1; return *this;}
        iterator operator++(int) {iterator retval = *this; ++(*this); return retval;}
        bool operator==(iterator other) const {return num == other.num;}
        bool operator!=(iterator other) const {return !(*this == other);}
        long operator*() {return num;}
        // iterator traits
        using difference_type = long;
        using value_type = long;
        using pointer = const long*;
        using reference = const long&;
        using iterator_category = std::forward_iterator_tag;
    };
    iterator begin() {return FROM;}
    iterator end() {return TO >= FROM? TO+1 : TO-1;}
};
31
Amir Kirsh

オプション3は、すべて同じtypedefsを記述する必要がありますが、さらに_iterator_traits<X>_をラップする必要があるため、オプション1の厳密に型指定されたバージョンです。

オプション2はソリューションとしては実行不可能です。一部の型を推測できます(たとえば、referencedecltype(*it)だけです)が、_iterator_category_を推測することはできません。イテレータがマルチパス保証を満たしているかどうかを再帰的に確認できないため、単にオペレーションの存在だけで_input_iterator_tag_と_forward_iterator_tag_を区別できません。さらに、イテレータが可変参照を生成する場合、これらと_output_iterator_tag_を実際に区別することはできません。どこかに明示的に提供する必要があります。

これでオプション1は終了します。すべての定型文を書くことに慣れる必要があると思います。私は、新しい手根管の支配者を歓迎します。

30
Barry