暴露自定义STL样式迭代的首选方法是什么?

Ðаn*_*Ðаn 8 c++ iterator stl

(另请参阅是否有一种很好的方法可以在C++中为自定义类型手写所有12个所需的Container函数?)


对于像这样的课程

namespace JDanielSmith {
class C
{
    const size_t _size;
    const std::unique_ptr<int[]> _data;

public:
    C(size_t size) : _size(size), _data(new int[size]) {}

    inline const int* get() const noexcept { return _data.get(); }
    inline int* get() noexcept { return _data.get(); }

    size_t size() const noexcept { return _size; }
};
}
Run Code Online (Sandbox Code Playgroud)

暴露迭代的首选方式是什么?我应该写begin()/ end()(和cbegin()/ cend())成员函数吗?

const int* cbegin() const {
    return get();
}
const int* cend() const {
    return cbegin() + size();
}
Run Code Online (Sandbox Code Playgroud)

或者这些应该是非会员职能?

const int* cbegin(const C& c) {
    return c.get();
}
const int* cend(const C& c) {
    return cbegin(c) + c.size();
}
Run Code Online (Sandbox Code Playgroud)

应该begin()/ end()有两个const和非const过载?

    const int* begin() const {
        return get();
    }
    int* begin() {
        return get();
    }
Run Code Online (Sandbox Code Playgroud)

还有其他事情需要考虑吗?是否有工具/技术使这个"容易正确"并减少锅炉板代码的数量?


一些相关问题/讨论包括:

Bri*_*ice 6

如果您希望它们与STL一致,那么有一个标准描述了您的类接口应该是什么样子.C++具有"概念"这一概念,它将给定类的要求限定为概念的充分实现.这几乎成了c ++ 11中的语言特性.

您可能感兴趣的概念是容器概念.正如你所看到的,以满足集装箱观的要求,需要begin,cbegin,end,和cend为成员函数(除其他事项外).

由于您将数据存储在数组中,因此您可能也对SequenceContainer感兴趣.

  • 容器中有一些东西,这个类目前没有,最重要的是复制.替代方案是:满足Boost.Range的要求,这是"你可以迭代并因此使用算法的东西"; 或者只是做足够的基于范围的循环工作. (2认同)

R S*_*ahu 1

我建议创建两组函数——成员函数和非成员函数——以实现最大的灵活性。

namespace JDanielSmith {
   class C
   {
      const size_t _size;
      const std::unique_ptr<int[]> _data;

      public:
      C(size_t size) : _size(size), _data(new int[size]) {}

      inline const int* get() const { return _data.get(); }
      inline int* get() { return _data.get(); }

      size_t size() const { return _size; }

      int* begin() { return get(); }
      int* end() { return get() + _size; }
      const int* begin() const { return get(); }
      const int* end() const { return get() + _size; }
      const int* cbegin() const { return get(); }
      const int* cend() const { return get() + _size; }

   };

   int* begin(C& c) { return c.begin(); }
   int* end(C& c) { return c.end(); }
   const int* begin(C const& c) { return c.begin(); }
   const int* end(C const& c) { return c.end(); }
   const int* cbegin(C const& c) { return c.begin(); }
   const int* cend(C const& c) { return c.end(); }
}
Run Code Online (Sandbox Code Playgroud)

如果您希望能够使用类型的对象C作为std::beginstd::endstd::cbegin和 的参数,则成员函数是必需的std::cend

如果您希望能够使用类型的对象C作为beginendcbegin和 的参数,则非成员函数是必需的cend。ADL 将确保找到此类用途的非成员函数。

int main()
{
   JDanielSmith::C c1(10);

   {
      // Non-const member functions are found
      auto b = std::begin(c1);
      auto e = std::end(c1);
      for (int i = 0; b != e; ++b, ++i )
      {
         *b = i*10;
      }
   }

   JDanielSmith::C const& c2 = c1;
   {
      // Const member functions are found
      auto b = std::begin(c2);
      auto e = std::end(c2);
      for ( ; b != e; ++b )
      {
         std::cout << *b << std::endl;
      }
   }

   {
      // Non-member functions with const-objects as argument are found
      auto b = begin(c2);
      auto e = end(c2);
      for ( ; b != e; ++b )
      {
         std::cout << *b << std::endl;
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

  • RSahu:这是通常推荐的做事方式,我不认为有理由删除它。@Guvante:我知道全局开始的好处,我只是没有看到 _custom_ 全局开始的好处。默认的看起来效果很好。 (4认同)
  • 我错过了什么吗?为什么每个人都实现自己的非成员“开始”和“结束”函数?为什么 `std::begin` 和 `std::end` 不够? (3认同)
  • @BrianFairservice:http://stackoverflow.com/questions/7593086/why-use-non-member-begin-and-end-functions-in-c11 (2认同)
  • “如果您希望能够使用 C 类型的对象作为 begin、end、cbegin 和 cend 的参数,则非成员函数是必需的”不,您不需要,默认的 `std::begin` 已经调用会员版。如果您确实无法添加成员版本(例如数组或第三方),则只需编写非成员版本。 (2认同)