我有一个与容器差不多的纯虚拟接口,
class IContainer
{
public:
virtual ~IContainer() = default;
virtual Element& operator[](size_t index) = 0;
virtual const Element& operator[](size_t index) const = 0;
virtual size_t size() const = 0;
};
我想对循环使用范围,所以我需要定义begin()和end()。为此,我还需要定义迭代器类型。
应该不是特别难,但是在我开始编码已经存在的东西之前,我还是想知道STL或Boost中是否有可以帮助的东西。
答案 0 :(得分:3)
这可能不是一个好主意,但是在这里添加for(:)
循环支持相对容易。我会很小的。
我将创建一个iteroid
,这是一个非迭代器,足以支持for(:)
循环。这需要++
,!=
和一元*
的支持,而没有其他要求。
template<class C>
struct index_iteroid {
decltype(auto) operator*()const {
return (*container)[i];
}
index_iteroid(index_iteroid const&)=default;
index_iteroid& operator=(index_iteroid const&)=default;
friend bool operator==(index_iteroid const& lhs, index_iteroid const& rhs) {
return std::tie(lhs.i, lhs.container)==std::tie(rhs.i, rhs.container);
}
friend bool operator!=(index_iteroid const& lhs, index_iteroid const& rhs) {
return !(lhs==rhs);
}
void operator++()&{
++i;
}
index_iteroid(C* c, std::size_t in):i(in), container(c) {}
private:
std::size_t i = 0;
C* container = nullptr;
};
现在我们使用它:
class IContainer
{
public:
virtual ~IContainer() = default;
virtual Element& operator[](size_t index) = 0;
virtual const Element& operator[](size_t index) const = 0;
virtual size_t size() const = 0;
index_iteroid<IContainer> begin() { return {this, 0}; }
index_iteroid<IContainer> end() { return {this, size()}; }
index_iteroid<IContainer const> begin() const { return {this, 0}; }
index_iteroid<IContainer const> end() const { return {this, size()}; }
};
就在那里。
void test( IContainer* cont ) {
if (!cont) return;
for(Element& e : *cont) {
// code
}
}
请原谅任何错别字。
现在,一个完整的迭代器所需要的代码大约是我的iteroid
的2-3倍,但是没有什么棘手的事情,大部分只是令人讨厌的样板代码。
该标准对您没有太大帮助。为了提高效率,您可以将计数迭代器与函数校准迭代器/生成器组合在一起,并使函数调用使用[]
。如果要将iteroid升级为迭代器,Boost还提供了一些实用程序,可以减少编写完整迭代器的过程。
答案 1 :(得分:1)
C ++不会像这样执行“接口”。惯用的方式是将IContainer
的(潜在)客户端改为在容器类型上进行模板化并仅调用values[index]
,或在迭代器类型上进行模板化并进行类似*(first + offset)
的调用。 / p>
在C ++ 20中,您将能够编写Container
Concept,其行为有点像接口定义,但是您已经可以将概念表达为已记录的需求。
如果您想使用类型擦除的随机访问“容器”,则可以使用boost::any_range<Element, boost::random_access_traversal_tag>