适用于
等课程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; }
};
}
公开迭代的首选方式是什么?我应该写begin()
/ end()
(以及cbegin()
/ 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();
}
begin()
/ end()
是否同时包含const
和非const
?
const int* begin() const {
return get();
}
int* begin() {
return get();
}
还有其他事情需要考虑吗?是否有工具/技术使这个&#34;容易正确&#34;并减少锅炉板代码的数量?
一些相关问题/讨论包括:
答案 0 :(得分:6)
如果您希望它们与STL一致,那么有一个标准描述了您的类接口应该是什么样子。 C ++有“概念”概念,它将给定类的要求限定为概念的充分实现。这几乎成了c ++ 11中的语言特性。
您可能感兴趣的概念是Container概念。如您所见,为了满足Container概念的要求,您需要begin
,cbegin
,end
和cend
作为成员函数(除其他外) 。
由于您将数据存储在数组中,因此您可能也对SequenceContainer感兴趣。
答案 1 :(得分:2)
我会选择C.
这里的主要问题是std::begin()
实际上并不适用于使用ADL查找非成员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_begin(x)
,它就会起作用。以及标准容器和原始数组。这方便地使成员与非成员讨论相对立。
是的,如果您希望公开const
和非const
,那么begin()
和朋友的const
和非const
重叠应该是{{1}}访问。
答案 2 :(得分: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(); }
}
如果您希望能够使用C
类型的对象作为std::begin
,std::end
,std::cbegin
和{{1}的参数,则必须使用成员函数}。
如果您希望能够使用std::cend
类型的对象作为C
,begin
,end
和{的参数,则必须使用非成员函数{1}}。 ADL将确保为此类用法找到非成员函数。
cbegin
答案 3 :(得分:-2)
为了创建有效的迭代器,必须确保std :: iterator_traits有效。这意味着您必须设置迭代器类别等。
迭代器应该实现iterator(),iterator(iterator&amp;&amp;),iterator(iterator const&amp;),operator ==,operator!=,operator ++,operator ++(int),operator *,operator =和operator-取代。添加运算符&lt;也是一个好主意。和操作员+如果可以的话(你不能总是,例如链表。)
template <typename T>
class foo
{
public:
using value_type = T;
class iterator
{
public:
using value_type = foo::value_type;
using iterator_category = std::random_access_iterator_tag;
// or whatever type of iterator you have...
using pointer = value_type*;
using reference = value_type&;
using difference_type = std::ptrdiff_t;
// ...
};
class const_iterator
{
// ...
};
iterator begin() { /*...*/ }
iterator end() { /*...*/ }
const_iterator cbegin() const { /*...*/ }
const_iterator cend() const { /*...*/ }
/* ... */
};
有关创建有效迭代器所需内容的更多信息,请参阅:http://en.cppreference.com/w/cpp/iterator/iterator_traits。 (注意:您还需要某些属性才能成为有效的&#34;容器&#34;,如.size())
理想情况下,你应该使用成员函数来开始和结束,但它不是必需的......你也可以重载std :: begin和std :: end。如果您不知道如何操作,我建议您使用成员函数。
你应该创建begin()const和end()const,但它应该是cbegin()的别名,永远不会与begin()相同!