【发布时间】:2011-06-10 06:26:16
【问题描述】:
有什么方法可以检查给定的迭代器是否属于 C++ 中的给定列表?
【问题讨论】:
有什么方法可以检查给定的迭代器是否属于 C++ 中的给定列表?
【问题讨论】:
您不能简单地遍历列表,将每个迭代器值与您的“候选人”进行比较。
C++03 标准对应用于来自不同容器的迭代器的 == 的有效性含糊不清(Mankarse 对 Nawaz 的答案链接 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2948.html#446 的评论),一些编译器(例如 VC++2005 调试模式)会发出警告,如果你这样做了,但尽管它实际上可能会根据你的编译器/库而可靠地工作 - 如果你不关心可移植性,请查看它的文档。
C++11 标准非常明确,不能将迭代器与不同的容器进行比较:
§ 24.2.5 前向迭代器的 == 域是相同底层序列上的迭代器的域。
所以,依赖operator==的这个问题的答案现在是有问题的,将来也是无效的。
您可以做的是沿着列表进行迭代,将元素的地址(即&*i)与其他迭代指向的对象的地址进行比较。
Mankarse 的评论警告说,这可能不适用于提供自己的 operator& 的对象。您可以使用 std::addressof 或 C++03 boost's version
Martin 的评论提到您必须假设您正在测试列表成员资格的候选迭代器是安全可取消引用的 - 即不等于它来自的容器上的 end() 迭代器。正如史蒂夫指出的那样——这是一个相当合理的前提,不应该让任何人感到惊讶。
(这对于所有标准容器都很好,因为存储的元素永远不会有相同的地址,但更一般地说,用户定义的容器可以允许不相等的迭代器处理相同的值对象(例如,支持循环或“flyweight 模式”样式优化),在这种情况下,这种方法会失败。不过,如果您编写这样的容器,您可能可以设计用于安全迭代器比较。)
实施:
template <class IteratorA, class IteratorB, class IteratorC>
inline bool range_contains(IteratorA from, const IteratorB& end,
const IteratorC& candidate)
{
while (from != end)
if (&*from++ == &*candidate)
return true;
return false;
}
注意事项:
begin() 返回 iterator 但 end() 返回 const_iterator 的容器。from 以外的迭代器由const 引用,因为迭代器有时可能是不平凡的对象(即太大而无法放入寄存器,复制起来相对昂贵)。值需要from,因为它将在整个范围内递增。【讨论】:
end()(或@987654339 @ 的空列表),再次取消引用它是 UB。真是一团糟! :-)
end 迭代器(属于 InputIterator 类别)的方法是将其与同一容器中使用== 或!= 的另一个迭代器进行比较。因此,除非调用者还告诉您迭代器来自哪个容器,否则您必须对迭代器提出一些要求以避免这种情况。