我觉得这里没有任何答案可以解释为什么我喜欢迭代器作为索引而不是索引到容器的一般概念。请注意,我使用迭代器的大部分经验实际上并非来自C ++,而是来自诸如Python之类的高级编程语言。
迭代器接口对您的函数的使用者施加了更少的要求,从而使使用者可以使用它做更多的事情。
如果您只需要能够转发即可,则开发人员不仅限于使用可索引的容器-他们可以使用任何实现类的类operator++(T&)
,operator*(T)
以及operator!=(const &T, const &T)
。
#include <iostream>
template <class InputIterator>
void printAll(InputIterator& begin, InputIterator& end)
{
for (auto current = begin; current != end; ++current) {
std::cout << *current << "\n";
}
}
// elsewhere...
printAll(myVector.begin(), myVector.end());
您的算法可以在您需要的情况下工作-在向量上进行迭代-但对于您不一定期望的应用程序也很有用:
#include <random>
class RandomIterator
{
private:
std::mt19937 random;
std::uint_fast32_t current;
std::uint_fast32_t floor;
std::uint_fast32_t ceil;
public:
RandomIterator(
std::uint_fast32_t floor = 0,
std::uint_fast32_t ceil = UINT_FAST32_MAX,
std::uint_fast32_t seed = std::mt19937::default_seed
) :
floor(floor),
ceil(ceil)
{
random.seed(seed);
++(*this);
}
RandomIterator& operator++()
{
current = floor + (random() % (ceil - floor));
}
std::uint_fast32_t operator*() const
{
return current;
}
bool operator!=(const RandomIterator &that) const
{
return current != that.current;
}
};
int main()
{
// roll a 1d6 until we get a 6 and print the results
RandomIterator firstRandom(1, 7, std::random_device()());
RandomIterator secondRandom(6, 7);
printAll(firstRandom, secondRandom);
return 0;
}
试图实现一个类似于此迭代器的操作的方括号运算符会很麻烦,而迭代器的实现则相对简单。方括号运算符还会影响类的功能-您可以将其索引到任意点-可能难以实现或效率低下。
迭代器还适合进行装饰。人们可以编写迭代器,这些迭代器在其构造函数中使用迭代器并扩展其功能:
template<class InputIterator, typename T>
class FilterIterator
{
private:
InputIterator internalIterator;
public:
FilterIterator(const InputIterator &iterator):
internalIterator(iterator)
{
}
virtual bool condition(T) = 0;
FilterIterator<InputIterator, T>& operator++()
{
do {
++(internalIterator);
} while (!condition(*internalIterator));
return *this;
}
T operator*()
{
// Needed for the first result
if (!condition(*internalIterator))
++(*this);
return *internalIterator;
}
virtual bool operator!=(const FilterIterator& that) const
{
return internalIterator != that.internalIterator;
}
};
template <class InputIterator>
class EvenIterator : public FilterIterator<InputIterator, std::uint_fast32_t>
{
public:
EvenIterator(const InputIterator &internalIterator) :
FilterIterator<InputIterator, std::uint_fast32_t>(internalIterator)
{
}
bool condition(std::uint_fast32_t n)
{
return !(n % 2);
}
};
int main()
{
// Rolls a d20 until a 20 is rolled and discards odd rolls
EvenIterator<RandomIterator> firstRandom(RandomIterator(1, 21, std::random_device()()));
EvenIterator<RandomIterator> secondRandom(RandomIterator(20, 21));
printAll(firstRandom, secondRandom);
return 0;
}
尽管这些玩具看起来很平凡,但不难想象使用迭代器和迭代器装饰器通过一个简单的界面即可完成强大的功能-例如,使用一个迭代器来装饰数据库结果的前向迭代器,该迭代器可从单个结果构造一个模型对象。这些模式可实现无限集的内存高效迭代,并且使用如我上面所写的过滤器,可能对结果进行延迟评估。
C ++模板的部分功能是迭代器接口,当将其应用于固定长度C数组之类时,它会退化为简单高效的指针算法,从而使其真正成为零成本的抽象。
some_iterator++
为++some_iterator
。后增量创建不必要的临时迭代器。