4

現在、ランダムアクセス反復子で API 要件を満たすことができるクラスがあります。ただし、実装が変更され、前方イテレータしか提供できない状況が想定できます。

したがって、呼び出し元がランダム アクセス機能を使用することを制限したいと思います。独自の実装 (たとえば、restricted_bar_iterator) を作成できることはわかっていますが、もっと単純な (つまり、コーディングが少なくて済む) ものはないかと考えていました。

class BAR { ... };

class FOO {
public:
    // Bad...clients may expect 'bar_iterator' to be random access...
    typedef std::vector<BAR>::iterator bar_iterator;

    bar_iterator begin_bar() const;
    bar_iterator end_bar() const;

    // Possible solution here!
    class restricted_bar_iterator :
        public std::iterator< std::forward_iterator_tag, BAR > { ... };
};


void baz()
{
    FOO foo;
    bar_iterator it = foo.begin_bar() + 5; // want a compile time error here!
}
4

2 に答える 2

4

Boost Iterator Adapterを使用した例を次に示します。intの代わりに使用しましたBAR

#include <boost/iterator/iterator_adaptor.hpp>
#include <vector>

struct iterator :
    public boost::iterator_adaptor<
        iterator,                    // the name of our class, see docs for details
        std::vector<int>::iterator,  // underlying base iterator
        boost::use_default,          // for value type
        boost::forward_traversal_tag // all the boilerplate for this!
    >
{
     // need this to convert from vector::iterator to ours
     explicit iterator(std::vector<int>::iterator i)
      : iterator::iterator_adaptor_(i) {}
};

int main()
{
    std::vector<int> v;
    iterator it(v.begin());
    ++it;    // OK
    it += 1; // ERROR
}

これは実質的std::vector<T>::iteratorに a を基本クラスとして使用しますが、前方反復子に対して定義された操作のみを許可します。欠点は、エラー メッセージです。あまり見栄えがよくありません。

于 2013-10-01T21:45:42.283 に答える
3

確かにいくつかのコーディングを行う必要がありますが、C++ 11 で削除済みとして定義するか、またはそれらを非公開にし、C++03 で実装されないようにします。

class FOO {
    // Bad...clients may expect 'bar_iterator' to be random access...
    typedef std::vector<BAR>::iterator bar_iterator_impl;

public:
    // Possible solution here!
    struct bar_iterator : bar_iterator_impl {
      bar_iterator& operator++() {
        ++static_cast<bar_iterator_impl&>(*this);
        return *this;
      }
      bar_iterator operator++(int) {
        bar_iterator copy(*this);
        ++*this;
        return copy;
      }

      typedef std::forward_iterator_tag iterator_category;    
      typedef std::iterator_traits<bar_iterator_impl>::value_type value_type;
      typedef std::iterator_traits<bar_iterator_impl>::difference_type difference_type;
      typedef std::iterator_traits<bar_iterator_impl>::pointer    pointer;
      typedef std::iterator_traits<bar_iterator_impl>::reference  reference;

    private:
      friend void operator+(bar_iterator const&, long);
      friend void operator+(long, bar_iterator const&);
      friend void operator-(bar_iterator const&, long);
      friend void operator-(long, bar_iterator const&);
    };

    bar_iterator begin_bar() const;
    bar_iterator end_bar() const;
};

ただし、これstd::vector<BAR>::iteratorは がクラス型である場合にのみ機能し、ポインターである可能性があり、その場合は派生できません。移植可能にするには、イテレータ API 全体を自分で定義する必要があります。

于 2013-10-01T21:32:26.530 に答える