当前位置: 首页 > 知识库问答 >
问题:

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

宦砚
2023-03-14

(另请参见是否有一种好方法可以不在C中手工编写自定义类型所需的所有12个容器函数?)

对于类,例如

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; }
};
}

公开迭代的首选方式是什么?我应该编写start()/end()(和cstart()/cend())成员函数?

const int* cbegin() const {
    return get();
}
const int* cend() const {
    return cbegin() + size();
}

或者这些应该是非成员函数?

const int* cbegin(const C& c) {
    return c.get();
}
const int* cend(const C& c) {
    return cbegin(c) + c.size();
}

是否应该同时具有常量和非常量重载?

    const int* begin() const {
        return get();
    }
    int* begin() {
        return get();
    }

还有什么需要考虑的吗?是否有工具/技术可以使这一点“很容易正确”并减少锅炉铭牌代码的数量?

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

  • 自定义容器是否应该具有自由开始/结束功能
  • 为什么在C 11中使用非成员begin和end函数
  • 何时使用std::begin和std::end而不是容器特定版本

共有3个答案

左华灿
2023-03-14

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

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(); }
}

如果希望能够将类型为C的对象用作参数,则必须使用成员函数。

如果您希望能够将类型为C的对象用作参数,仅用于开始、结束、cbegin和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;
      }
   }
}
施英哲
2023-03-14

我选择C选项。

这里的主要问题是,对于使用ADL查找非成员,std::begin()实际上不起作用。因此,真正的解决方案是编写自己的,这样做:

namespace details {
    using std::begin;

    template <class C>
    constexpr auto adl_begin(C& c) noexcept(noexcept(begin(c)))
        -> decltype(begin(c))
    {
        return begin(c);
    }
}

using details::adl_begin;

现在,无论您是作为成员函数还是非成员函数编写begin(),只要在任何地方都使用adl\u begin(x)就可以了。以及标准容器和原始阵列。这方便地避开了成员与非成员的讨论。

是的,如果您想公开const和non-code>const访问权限,您应该拥有begin()和friends的const和non-code重载。

韶云瀚
2023-03-14

如果希望类接口与STL一致,那么有一个标准描述类接口的外观。C有这样一个“概念”的概念,它规定了给定类的需求,以充分实现一个概念。这几乎成为c 11中的一个语言特性。

您可能感兴趣的一个概念是容器概念。如您所见,为了满足容器概念的要求,您需要开始cstartendcend作为成员函数(除其他外)。

因为看起来您正在将数据存储在一个数组中,所以您可能还对SequenceContainer感兴趣。

 类似资料:
  • 本文向大家介绍Android EditText自定义样式的方法,包括了Android EditText自定义样式的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Android EditText自定义样式的方法。分享给大家供大家参考,具体如下: 1.去掉边框 EditText的background属性设置为@null就搞定了:android:background="@null" sty

  • log4j2留档显示了生成自定义组件(如附加程序、过滤器和查找)的首选方法。但是,还不清楚如何确保这些自定义组件被日志框架拾取并可由日志配置使用。 在类路径中放置了一个带有正确注释的自定义appender之后,我还需要做些什么才能开始将其包含在我的log4j2中。xml文件,并已被日志框架拾取? 为了提供一个例子,如果我用以下注释custon appender: 我该如何在log4j2中这样拾取和

  • 问题内容: 在JavaScript中定义枚举的首选语法是什么?就像是: 还是有更好的成语? 问题答案: 从1.8.5开始,可以密封和冻结对象,因此将以上定义为: 要么 和瞧!JS枚举。 但是,这不会阻止您为变量分配不需要的值,这通常是枚举的主要目标: 确保类型安全性(使用枚举或其他方式)的程度更高的一种方法是使用诸如TypeScript或Flow之类的工具。 不需要引号,但为了保持一致性,我保留了

  • 我目前正在尝试自定义首选项部分的颜色。但我不知道该怎么做。 在我的应用程序中,我有两个主题:黑暗主题和光明主题。这是用户选择的一个选项。在我的主要活动中,我设置了用户选择的主题。 在我使用 attr 定义要显示的颜色之后。 当前列表首选项: 代码:style.xml 就像我说的,我已经试过解决办法了。我该怎么办? 非常感谢托马斯 编辑我将preferenceActivity更改为preferenc

  • 本文向大家介绍thinkPHP3.2实现分页自定义样式的方法,包括了thinkPHP3.2实现分页自定义样式的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了thinkPHP3.2实现分页自定义样式的方法。分享给大家供大家参考,具体如下: 下面是一个Tp3.2的自定义分页,这个方法也是在看过一个网友的博客之后受到启发这么写的。经过了一些修改,大家在看到代码之后也可以进行修改自定义样式;

  • 问题内容: 假设我有一个普通对象列表,然后可以用来呈现子级列表。那么将对象插入其中的正确方法是什么? 以下是我认为它将起作用的唯一方法,因为您不能像文档中提到的那样直接更改。 这对我来说似乎很丑。有没有更好的办法? 问题答案: 返回一个新数组,所以你可以做 另一个选择是React的不变性助手