可以在预期正向迭代器的地方使用输入迭代器吗?

时间:2011-06-23 04:15:06

标签: c++ stl iterator

据我所知,迭代器类别的层次结构如下:

Random access -> Bi-directional -> Forward -> Input
                                           -> Output

正确?

我一直认为有一条规则,如果算法需要特定类型的迭代器,您可以在链上提供类别的迭代器,但不能向下。所以我正在阅读this answer,其中ildjarn 建议使用std::ifstreamstd::istream_iteratorstd::search建议(后来自行更正)以查找数据在一个文件中。我即将评论你不能这样做,因为search期望转发迭代器,istream_iterator是一个输入迭代器。但为了确保,我尝试了这个:

std::istringstream iss("Elephant hats for sale.");
std::istream_iterator<char> begin(iss), end;

std::string sub("hat");
auto i = std::search(begin, end, sub.begin(), sub.end());

我没想到它会编译,但确实如此。然而,结果似乎没用,因为如果我遵循它:

while(i != end)
{
    std::cout << *i;
    ++i;
}

没有输出。所以,我的问题是:我的编译器是否因允许使用search拨打istream_iterator而出错?或者没有规则阻止这类事情?

1 个答案:

答案 0 :(得分:17)

  

可以在需要前向迭代器的地方使用输入迭代器吗?

没有。输入迭代器和前向迭代器之间的区别在于输入迭代器是“单通道”迭代器,而前向迭代器是“多通道”迭代器。

一旦推进输入迭代器,就无法再访问范围中的前一个元素。如果你复制了一个输入迭代器,那么两个迭代器都会保持有效,直到你推进其中一个迭代器为止;那么另一个就不再有效了。

使用正向迭代器,您可以多次遍历序列,您可以同时拥有迭代器的多个可用副本,您可以同时在序列中使用多个迭代器,并且可以取消引用迭代器在你再次推进它之前,你想要多次。

  

所以,我的问题是:我的编译器是否因允许我使用istream_iterator进行搜索而出错?

编译器必须拒绝代码。

规则是您必须确保传递函数所需的正确类型的迭代器。有时,如果传递错误类型的迭代器,则会出现编译错误。有时程序会编译但无法正常运行。有时事情看起来会正常工作。如果违反调用函数的要求,结果将不确定。


通用算法通常通过假设提供的类型参数实际满足要求来对其类型参数施加要求。因此,例如,仅适用于随机访问迭代器的算法将通过执行仅适用于随机访问迭代器(例如it + 1)的某些操作来“强制执行”此要求。如果迭代器不支持该操作(此处为operator+(iterator, int)),则代码将无法编译。

问题在于无法通过这种方式区分输入迭代器和转发迭代器:您可以对它们进行递增和取消引用;不同之处在于您可以执行每个操作的次数以及执行这些操作的顺序。因此,像std::search这样的算法将使用*it++it,这对于输入迭代器来说“正常”,至少在代码编译时是这样。

理论上,算法可以使用std::iterator_traits类模板来确定迭代器是输入迭代器还是前向迭代器;我不知道C ++语言标准是否允许这样做。如果库做到了这一点,你可能会得到代码的编译错误,这会更好。