【问题标题】:Why doesn't std::pair have iterators?为什么 std::pair 没有迭代器?
【发布时间】:2012-11-24 20:00:10
【问题描述】:

为什么std::pair 没有迭代器?

std::pair 应提供 iteratorconst_iterator 以及 begin()end() -- 仅适用于他们的两个成员。

我认为这会很有用,因为这样我们就可以将它们传递给期望可迭代的模板函数,例如 vectorset

这样做有什么缺点吗?

【问题讨论】:

  • std::pair<int, std::string>。迭代器仅适用于同构容器。
  • 虽然std::pair 有时被用作一个范围,但它并没有要求甚至鼓励这样使用——所以专门针对它不会太大。 C++11 的早期草案实际上曾经有过这一点。见stackoverflow.com/questions/6167598/…
  • 如果您发现自己想要将对象传递给此类模板函数,那么您可能应该使用std::array<T, 2> 而不是std::pair<T>

标签: c++ stl std-pair


【解决方案1】:

一个原因是一对中的两个元素可以是不同的类型。这不适合迭代器模型。

元组也是如此,拥有迭代器可能会更有吸引力。

如果您需要一个固定长度的廉价同质容器,您可以使用std::array<T, n>

【讨论】:

  • 标准有 std::pair std::equal_range
  • @QuentinUK 你的评论对我们这些不知道这是做什么的人没有帮助。
  • 我会给出更长的解释,但在评论中允许的字符数有限的情况下这是不可能的。至少可以谷歌了解更多信息。
【解决方案2】:

std::pair 的目的不是作为一个传统的容器,而是作为一个元组,允许将两个潜在的异构对象视为一个对象。

此外,因为您可以直接访问该对的两个部分,并且因为配对的类型可能不相同,所以迭代器没有意义。

【讨论】:

    【解决方案3】:

    我认为除了它仅适用于 pair<T,T> 而不是 pair<T,U> 之外没有任何特别的缺点。

    #include <utility>
    #include <iterator>
    #include <vector>
    #include <iostream>
    
    namespace itpair {
        template <typename T>
        struct pair_iterator : std::iterator<std::forward_iterator_tag, T> {
            std::pair<T,T> *container;
            int idx;
            pair_iterator(std::pair<T,T> *container, int idx) : container(container), idx(idx) {}
            T &operator*() const {
                return idx ? container->second : container->first;
            }
            T *operator->() const {
                return &*this;
            }
            friend pair_iterator &operator++(pair_iterator &self) {
                self.idx += 1;
                return self;
            }
            friend pair_iterator operator++(pair_iterator &self, int) {
                pair_iterator result = self;
                ++self;
                return result;
            }
            friend bool operator==(const pair_iterator &self, const pair_iterator &other) {
                return self.container == other.container && self.idx == other.idx;
            }
            friend bool operator!=(const pair_iterator &self, const pair_iterator &other) {
                return !(self == other);
            }
        };
    
        template <typename T>
        pair_iterator<T> begin(std::pair<T,T> &p) {
            return pair_iterator<T>(&p, 0);
        }
        template <typename T>
        pair_iterator<T> end(std::pair<T,T> &p) {
            return pair_iterator<T>(&p, 2);
        }
    }
    
    int main() {
        std::pair<int,int> p = std::make_pair(1, 2);
        using namespace itpair;
        std::vector<int> v(begin(p), end(p));
        std::cout << v[0] << " " << v[1] << "\n";
    }
    

    当然你也想要const_iterator,接下来你会想要它是随机访问的(这意味着更多的操作员)。

    不过,正如大家所说,pair 的真正用途并非如此。它只是不是一个容器。

    【讨论】:

      【解决方案4】:

      我想出了这个解决方案。不是很“性感”,但应该可以:

      #include <type_traits>
      #include <iterator>
      #include <utility>
      
      #include <boost/optional.hpp>
      
      namespace pair_iterator {
      
      template <class A, class B, class Pair>
      class PairIterator {
      public:
          using iterator_category = std::random_access_iterator_tag;
          using value_type = std::common_type_t<A, B>;
          using difference_type = std::ptrdiff_t;
          using pointer = std::add_pointer_t<value_type>;
          using reference = std::add_lvalue_reference_t<value_type>;
          using const_reference = std::add_lvalue_reference_t<const value_type>;
      private:
          boost::optional<Pair &> pair = {};
          difference_type index = 2;
      public:
          PairIterator(
              const boost::optional<Pair &> &pair = {},
              difference_type index = 2
          ) : pair(pair), index(index) {}
      
          // Iterator
      
          PairIterator(PairIterator&&) = default;
          PairIterator(const PairIterator&) = default;
          PairIterator &operator =(PairIterator&&) = default;
          PairIterator &operator =(const PairIterator&) = default;
          ~PairIterator() = default;
      
          void swap(PairIterator &other) {
              std::swap(pair, other.pair);
              std::swap(index, other.index);
          }
      
          reference operator *() {
              return index == 0 ? pair->first : pair->second;
          }
      
          const_reference operator *() const {
              return index == 0 ? pair->first : pair->second;
          }
      
          PairIterator &operator ++() {
              ++index;
              return *this;
          }
      
          // InputIterator
      
          bool operator ==(const PairIterator &other) const {
              return index == other.index;
          }
      
          bool operator !=(const PairIterator &other) const {
              return index != other.index;
          }
      
          PairIterator operator ++(int) const {
              return { pair, index+1 };
          }
      
          // ForwardIterator
      
          // BidirectionalIterator
      
          PairIterator &operator --() {
              --index;
              return *this;
          }
      
          PairIterator operator --(int) const {
              return { pair, index-1 };
          }
      
          // RandomAccessIterator
      
          PairIterator &operator +=(difference_type n) {
              index += n;
              return *this;
          }
      
          PairIterator operator +(difference_type n) const {
              return { pair, index+n };
          }
      
          PairIterator &operator -=(difference_type n) {
              index -= n;
              return *this;
          }
      
          PairIterator operator -(difference_type n) const {
              return { pair, index-n };
          }
      
          difference_type operator -(const PairIterator &other) const {
              return index - other.index;
          }
      
          reference operator [](difference_type n) {
              return (index+n) == 0 ? pair->first : pair->second;
          }
      
          const_reference operator [](difference_type n) const {
              return (index+n) == 0 ? pair->first : pair->second;
          }
      
          bool operator <(const PairIterator &other) const {
              return index < other.index;
          }
      
          bool operator >(const PairIterator &other) const {
              return index > other.index;
          }
      
          bool operator <=(const PairIterator &other) const {
              return index <= other.index;
          }
      
          bool operator >=(const PairIterator &other) const {
              return index >= other.index;
          }
      };
      
      template <class A, class B>
      auto begin(std::pair<A, B> &pair) ->
      PairIterator<A, B, std::pair<A, B>> {
          return { pair, 0 };
      }
      
      template <class A, class B>
      auto end(std::pair<A, B> &pair) ->
      PairIterator<A, B, std::pair<A, B>> {
          return { pair, 2 };
      }
      
      template <class A, class B>
      auto begin(const std::pair<A, B> &pair) ->
      PairIterator<const A, const B, const std::pair<A, B>> {
          return { pair, 0 };
      }
      
      template <class A, class B>
      auto end(const std::pair<A, B> &pair) ->
      PairIterator<const A, const B, const std::pair<A, B>> {
          return { pair, 2 };
      }
      
      } // namespace pair_iterator
      
      namespace std {
      
      using pair_iterator::begin;
      using pair_iterator::end;
      
      } // namespace std
      

      【讨论】:

        猜你喜欢
        • 2018-08-13
        • 2012-03-04
        • 2012-04-27
        • 2016-04-16
        • 2015-01-07
        • 2010-09-11
        • 1970-01-01
        • 2013-11-08
        • 1970-01-01
        相关资源
        最近更新 更多