据我所知,迭代器类别的层次结构如下:
Random access -> Bi-directional -> Forward -> Input
-> Output
Run Code Online (Sandbox Code Playgroud)
正确?
我一直认为有一个规则,如果算法需要特定类型的迭代器,你可以在链上提供类别的迭代器,但不能向下.所以我正在阅读这个答案,其中ildjarn 建议使用std::ifstreamwith std::istream_iterator并std::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());
Run Code Online (Sandbox Code Playgroud)
我没想到它会编译,但确实如此.但是,结果似乎没用,因为如果我遵循它:
while(i != end)
{
std::cout << *i;
++i;
}
Run Code Online (Sandbox Code Playgroud)
没有输出.所以,我的问题是:我的编译器错误地允许我的调用search使用istream_iterator?或者没有规则阻止这种事情?
Jam*_*lis 17
可以在预期正向迭代器的地方使用输入迭代器吗?
否.输入迭代器和前向迭代器之间的区别在于输入迭代器是"单通道"迭代器,而前向迭代器是"多通道"迭代器.
推进输入迭代器后,您将无法再访问该范围中的先前元素.如果你复制了一个输入迭代器,那么两个迭代器都会保持有效,直到你推进其中一个迭代器为止; 那么另一个就不再有效了.
使用正向迭代器,您可以多次迭代序列,您可以同时拥有迭代器的多个可用副本,您可以同时在序列中使用多个迭代器,并且可以多次取消引用迭代器如你所愿,再次推进它之前.
所以,我的问题是:我的编译器错误地允许我的调用使用搜索
istream_iterator?
没有规则编译器必须拒绝代码.
规则是您必须确保传递函数所需的正确类型的迭代器.有时,如果传递错误类型的迭代器,则会出现编译错误.有时程序会编译但无法正常运行.有时事情看起来会正常工作.如果违反调用函数的要求,结果将不确定.
通用算法通常通过假设提供的类型参数实际满足要求而对其类型参数施加要求.因此,例如,仅适用于随机访问迭代器的算法将通过执行仅适用于随机访问迭代器(例如it + 1)的某些操作来"强制执行"此要求.如果迭代器不支持该操作(operator+(iterator, int)此处),则代码将无法编译.
问题是没有办法以这种方式区分输入迭代器和转发迭代器:你可以增加和取消引用它们; 不同之处在于您可以执行每个操作的次数以及执行这些操作的顺序.所以,算法一样std::search会用*it和++it,从而将"工作"就好了输入迭代器,至少只要该代码将编译.
理论上,算法可以使用std::iterator_traits类模板来确定迭代器是输入迭代器还是前向迭代器; 我不知道C++语言标准是否允许这样做.如果库做到了这一点,你可能会得到代码的编译错误,这会更好.