让我们来考虑一个非常基本的范围适配器类,它围绕一个范围进行打包,并在遍历适配器时迭代原始范围的每个其他元素。在范围适配器的迭代器类中实现运算符 - >
for (const auto & e : everyOtherElement(originalRange))
当写这样的范围适配器类,需要编写一个相应的迭代器类为该适配器,使其可迭代和行为像期望的。
这样的迭代器类应该实现您希望它支持的“概念”所需的所有内容,例如InputIterator
。除其他外,我们应该执行operator*
以返回对代表元素的引用,以及operator->
,以便it->member
访问该元素的成员。
我认为这将是一个好主意,只是“前进”这些运营商底层迭代器适配器环绕的实现(让我们忘掉常量性了一会儿):
struct everyOtherElement {
OriginalIterator b, e; // The begin and end we wrap around
// ...
struct iterator {
OriginalIterator it;
auto operator*() { return *it; } // <------
auto operator->() { return it.operator->(); } // <------
// ...
};
};
但是,如果OriginalIterator
是指针类型,则operator->
无法编译,就像大多数std::vector
实现以及原始数组一样。由于这种迭代器是非类型的,因此不允许编写it.operator->()
。
我该如何实现operator->
才能使迭代器尽可能透明?我是否应该按照operator*
执行operator->
,即像编写(*it).m
而不是it->m
。我猜这会失败,如果一些迭代器实现它们意味着不同的事情...(虽然这将是邪恶的,不是吗?或者被InputIterator
概念禁止?)
它是一个好主意来实现它作为刚刚返回的原始迭代器,因为operator->
是递归自动应用,只要返回一个非指针?
auto operator->() { return it; }
正如我假设有涉及模板,我会建议仅使用SFINAE /标签调度来选择实现,具体取决于OriginalIterator是否为指针。 –