输入迭代器可以用在需要前向迭代器的地方吗?
据我所知,迭代器类别的层次结构如下:
To my knowledge, the hierarchy of iterator categories goes like this:
Random access -> Bi-directional -> Forward -> Input
-> Output
正确吗?
我一直认为有一个规则,如果一个算法需要一个特定类型的迭代器,你可以在链上提供类别的迭代器,但不能向下.所以我正在阅读 这个答案,ildjarn suggests 建议(后来更正自己)使用 std::ifstream
和 std::istream_iterator
和 std::search
在文件中查找数据.我正要评论说你不能这样做,因为 search
需要 Forward 迭代器,而 istream_iterator
是一个 Input 迭代器.但为了确保,我尝试了这个:
I always thought there was a rule, that if an algorithm expects a particular type of iterator, you can provide iterators of categories up the chain, but not down. So I was reading this answer, where ildjarn suggests suggested (then later corrected himself) using std::ifstream
with std::istream_iterator
and std::search
to find data in a in a file. I was about to comment that you can't do that, because search
expects Forward iterators, and istream_iterator
is an Input iterator. But just to make sure, I tried this:
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());
我没想到它会编译,但它确实编译了.但是,结果似乎毫无用处,因为如果我按照以下方式进行操作:
I didn't expect it to compile, but it did. However, the results seem to be useless because if I follow it with this:
while(i != end)
{
std::cout << *i;
++i;
}
没有输出.所以,我的问题是:我的编译器是否错误地允许我使用 istream_iterator
调用 search
?还是没有规则阻止这种事情发生?
There is no output. So, my question is this: Is my compiler in error for allowing my call to search
using istream_iterator
? Or are there no rules preventing this sort of thing?
推荐答案
输入迭代器可以用在需要前向迭代器的地方吗?
Can input iterators be used where forward iterators are expected?
没有.输入迭代器和前向迭代器之间的区别在于,输入迭代器是单程"迭代器,而前向迭代器是多程"迭代器.
No. The difference between an input iterator and a forward iterator is that an input iterator is a "single-pass" iterator but a forward iterator is a "multi-pass" iterator.
一旦你推进了一个输入迭代器,你就不能再访问该范围内的先前元素.如果您复制输入迭代器,则两个迭代器都保持有效,直到您推进其中一个;然后另一个不再有效.
Once you advance an input iterator, you can no longer access the previous elements in the range. If you make a copy of an input iterator, both iterators remain valid until you advance one of them; then the other ceases to be valid.
使用前向迭代器,您可以对序列进行任意次数的迭代,一次可以拥有多个可用的迭代器副本,可以同时在序列中使用多个迭代器,还可以取消对迭代器的引用在再次推进之前,你想多少次都可以.
With a forward iterator, you can iterate over the sequence any number of times, you can have multiple usable copies of an iterator at once, you can use multiple iterators into the sequence at the same time, and you can dereference an iterator as many times as you'd like before advancing it again.
所以,我的问题是:我的编译器是否因允许我使用 istream_iterator
进行搜索而出错?
So, my question is this: Is my compiler in error for allowing my call to search using
istream_iterator
?
没有规定编译器必须拒绝代码.
There is no rule that the compiler must reject the code.
规则是您必须确保传递函数所需的正确类型的迭代器.有时如果你传递了错误类型的迭代器,你会得到一个编译错误.有时程序会编译但无法正常运行.有时事情会看起来正常工作.如果违反调用函数的要求,结果是不确定的.
The rule is that you must be sure to pass the right type of iterator that is required by the function. Sometimes if you pass the wrong type of iterator you get a compilation error. Sometimes the program will compile but will not function correctly. Sometimes things will appear to work correctly. The results are undefined if you violate the requirements of calling the function.
通用算法通常通过假设提供的类型参数实际满足要求来对其类型参数施加要求.因此,例如,仅适用于随机访问迭代器的算法将通过执行一些仅适用于随机访问迭代器的操作(例如 it + 1
)来强制"此要求.如果迭代器不支持该操作(此处为operator+(iterator, int)
),代码将无法编译.
Generic algorithms usually impose requirements on their type parameters by assuming that the type arguments provided actually meet the requirements. So, for example, an algorithm that only works with random access iterators will "enforce" this requirement by performing some operation that only works with random access iterators (e.g. it + 1
). If the iterator doesn't support that operation (operator+(iterator, int)
here), the code will fail to compile.
问题在于无法通过这种方式区分输入迭代器和前向迭代器:您可以对它们进行递增和取消引用;不同之处在于您可以执行每个操作的次数以及您可以执行这些操作的顺序.因此,像 std::search
这样的算法将使用 *it
和 ++it
,这对于输入迭代器来说工作"得很好,至少在代码可以编译的范围内.
The problem is that there is no way to distinguish between input iterators and forward iterators this way: you can increment and dereference both of them; the difference is in how many times you can perform each of those operations and the sequence in which you can perform those operations. So, an algorithm like std::search
will use *it
and ++it
, which will "work" just fine for input iterators, at least insofar as the code will compile.
理论上,算法可以使用 std::iterator_traits
类模板来确定迭代器是输入迭代器还是前向迭代器;我不知道 C++ 语言标准是否允许这样做.如果库这样做了,您的代码可能会出现编译错误,这样会更好.
In theory, an algorithm could use the std::iterator_traits
class template to determine whether an iterator is an input iterator or a forward iterator; I don't know whether that would be permitted by the C++ language standard. If the library did that, you could get a compilation error for your code, which would be better.
相关文章