我可以/应该从 STL 迭代器继承吗?

2022-01-07 00:00:00 iterator c++ stl

我可以/应该从 STL 迭代器继承来实现我自己的迭代器类吗?如果没有,为什么不呢?

Can/Should i inherit from STL iterator to implement my own iterator class? If no, why not?

推荐答案

简短回答

许多人认为 std::iterator 类与常规类型别名相比并没有提供太多,甚至通过不显式提供名称和依赖模板参数的顺序来混淆它们反而.它在 C++17 中已被弃用,并且可能会在几年后消失.

Short answer

Many consider that the class std::iterator does not offer much compared to regular type aliases, and even obfuscates them a bit by not explicitly providing the names and relying on the order of the template parameters instead. It is deprecated in C++17 and is likely to be gone in a few years.

这意味着您不应再使用 std::iterator.如果您对完整故事感兴趣,可以阅读下面的整篇文章(由于它在弃用提案之前已开始,因此有一些冗余).

This means that you shouldn't use std::iterator anymore. You can read the whole post below if you're interested in the full story (there's a bit of redundancy since it has been started before the deprecation proposal).

如果您对历史不感兴趣,可以忽略以下所有内容.以下片段甚至多次自相矛盾.

截至今天(C++11/C++14),标准似乎暗示从 std::iterator 继承来实现自定义迭代器不再是一个好主意.这里简单解释一下,来自N3931:

As of today (C++11/C++14), the standard seems to imply that it isn't a good idea anymore to inherit from std::iterator to implement custom iterators. Here is a brief explanation, from N3931:

尽管标准已经犯了十几次这个错误,但我建议不要将 directory_iteratorrecursive_directory_iterator 描述为从 std::iterator 派生,因为这是对实现的约束性要求.相反,它们应该被描述为具有适当的 typedef,并由实现者决定如何提供它们.(使用 is_base_of 的用户可以观察到差异,而不是他们应该问这个问题.)

Although the Standard has made this mistake almost a dozen times, I recommend not depicting directory_iterator and recursive_directory_iterator as deriving from std::iterator, since that's a binding requirement on implementations. Instead they should be depicted as having the appropriate typedefs, and leave it up to implementers to decide how to provide them. (The difference is observable to users with is_base_of, not that they should be asking that question.)

[2014-02-08 Daniel 评论并提供措辞]

这个问题基本上类似于unary_function和朋友中派生的要求的那种解决方案N3198" rel="noreferrer">N3198,我也非常赞成在这里遵循这种精神.我想补充一点,基本上所有较新"的迭代器类型(例如 regex 相关迭代器)也不是从 std::iterator 派生的.

This issue is basically similar to the kind of solution that had been used to remove the requirement to derive from unary_function and friends as described by N3198 and I'm strongly in favour to follow that spirit here as well. I'd like to add that basically all "newer" iterator types (such as the regex related iterator) don't derive from std::iterator either.

该论文引用了 N3198,它本身声明它遵循了 N3145.弃用仅用于提供 typedef 的类的原因如下:

The paper cites N3198 which itself states that it follows the deprecation discussed in N3145. The reasons for deprecating the classes that only exist to provide typedefs are given as such:

我们在概念方面的经验让我们相信,如果类型和函数的可用性足够,很少需要依赖特定的基类派生类关系.新的语言工具允许我们即使在没有语言支持的概念的情况下也能推断出类类型中类型名的存在,这会在它们之间引入弱得多的耦合.用关联类型替换继承的另一个优点是,这将减少出现歧义的情况的数量:如果一个类型从 unary_functionbinary_function 继承,这很容易发生(这是有道理的,如果函子既是一元函数对象又是二元函数对象).

Our experience with concepts gives us confidence that it is rarely necessary to depend on specific base class-derived class relations, if availability of types and functions is sufficient. The new language tools allow us even in the absence of language-supported concepts to deduce the existence of typenames in class types, which would introduce a much weaker coupling among them. Another advantage of replacing inheritance by associated types is the fact, that this will reduce the number of cases, where ambiguities arise: This can easily happen, if a type would inherit both from unary_function and binary_function (This makes sense, if a functor is both an unary and a binary function object).

tl;dr:仅提供 typedef 的类现在被视为无用.此外,它们在不需要时会增加耦合,更加冗长,并且在某些极端情况下可能会产生不必要的副作用(请参阅前面的引文).

tl;dr: classes which only provide typedefs are now deemed useless. Moreover, they increase coupling when it is not needed, are more verbose, and can have unwanted side effects in some corner cases (see the previous quotation).

更新: N4245 的第 2438 期 似乎实际上与我之前断言的内容相矛盾:

Update: issue 2438 from N4245 seems to actually contradict what I asserted earlier:

为了 LWG 的方便,将九个 STL 迭代器描述为从 std::iterator 派生以获取它们的 iterator_category/etc.类型定义.不幸的是(并且无意中),这也强制要求继承,这是可观察的(不仅通过 is_base_of,还通过重载解析).这是不幸的,因为它混淆了用户,他们可能会被误导认为他们自己的迭代器必须从 std::iterator 派生,或者重载函数以获取 std::iterator有点意思.这也是无意的,因为 STL 最重要的迭代器,容器迭代器,不需要从 std::iterator 派生.(有些甚至可以是原始指针.)最后,这不必要地限制了实现者,他们可能不想从 std::iterator 派生.(例如,为了简化调试器视图.)

For LWG convenience, nine STL iterators are depicted as deriving from std::iterator to get their iterator_category/etc. typedefs. Unfortunately (and unintentionally), this also mandates the inheritance, which is observable (not just through is_base_of, but also overload resolution). This is unfortunate because it confuses users, who can be misled into thinking that their own iterators must derive from std::iterator, or that overloading functions to take std::iterator is somehow meaningful. This is also unintentional because the STL's most important iterators, the container iterators, aren't required to derive from std::iterator. (Some are even allowed to be raw pointers.) Finally, this unnecessarily constrains implementers, who may not want to derive from std::iterator. (For example, to simplify debugger views.)

总而言之,我错了,@aschepler 是对的:它可以使用,但肯定不是必需的 - 也不气馁.整个让我们删除 std::iterator"的东西存在是为了标准不限制标准库实现者.

To sum up, I was wrong, @aschepler was right: it can be used, but it is certainely not required - it isn't discouraged either. The whole "let's remove std::iterator" thing exists for the standard not to constrain the standard library implementers.

第 3 轮: P0174R0 建议弃用 std::iterator 以便将来可能删除.该提案已经很好地解释了为什么应该弃用它,所以我们开始吧:

Round 3: P0174R0 proposes to deprecate std::iterator for a possible removal in the future. The proposal is already pretty good at explaining why it should be deprecated, so here we go:

对于读者来说,一长串 void 参数比简单地在类定义本身中提供预期的 typedef 更不清楚,这是当前工作草案采用的方法,遵循 C++14 中设置的模式,我们弃用了从 unary_function 和 binary_function 的整个函子库的派生.

The long sequence of void arguments is much less clear to the reader than simply providing the expected typedefs in the class definition itself, which is the approach taken by the current working draft, following the pattern set in C++14 where we deprecated the derivation throughout the library of functors from unary_function and binary_function.

除了降低清晰度之外,迭代器模板还为粗心的人设置了一个陷阱,因为在典型用法中它将是一个依赖基类,这意味着它不会在从类内部或它的类中查找名称时进行查看成员函数.这导致用户惊讶地试图理解为什么以下简单用法不起作用:

In addition to the reduced clarity, the iterator template also lays a trap for the unwary, as in typical usage it will be a dependent base class, which means it will not be looking into during name lookup from within the class or its member functions. This leads to surprised users trying to understand why the following simple usage does not work:

#include <iterator>

template <typename T>
struct MyIterator : std::iterator<std::random_access_iterator_tag, T> {
   value_type data;  // Error: value_type is not found by name lookup 

   // ... implementations details elided ...
};

单是清晰的原因就足以说服 LWG 更新标准库规范,不再强制要求标准迭代器适配器源自 std::iterator,因此在标准本身中不再使用此模板.因此,它看起来很适合弃用.

The reason of clarity alone was sufficient to persuade the LWG to update the standard library specification to no longer mandate the standard iterator adapators as deriving from std::iterator, so there is no further use of this template within the standard itself. Therefore, it looks like a strong candidate for deprecation.

这变得有点累人,而且似乎不是每个人都同意,所以我会让你得出自己的结论.如果委员会最终决定不推荐使用 std::iterator,那么它就会清楚地表明您不应再使用它.请注意后续论文 强调了对删除 std::iterator 的大力支持:

This is becoming a bit tiring and not everyone seems to agree, so I will let you draw your own conclusions. If the committee eventually decides that std::iterator should be deprecated, then it will make it pretty clear that you shouldn't use it anymore. Note that the follow-up paper highlights a great support for the removal of std::iterator:

2016 年杰克逊维尔更新:

投票:弃用 iterator for C++17??
SF F N A SA
6 10 1 0 0

Poll: Deprecate iterator for C++17??
SF??F???N???A???SA
6????10??1????0???0

在上述投票结果中,SF、F、N、A 和 SA 代表强烈支持、支持、中立、反对和强烈反对>.

In the above poll results, SF, F, N, A and SA stand for Strongly For, For, Neutral, Against and Strongly Against.

奥卢更新,2016 年:

投票:仍要弃用 std::iterator?
SF F N A SA
3 6 3 2 0

Poll: Still want to deprecate std::iterator?
SF F N A SA
3???6??3??2??0

P0619R1 提出删除 std::iterator,可能在 C++20 中尽快,并建议增强 std::iterator_traits 以便它可以自动推断类型 Difference_typepointerreferencestd::iterator 在未明确提供时的作用相同.

P0619R1 proposes to remove std::iterator, possibly as soon as C++20, and also proposes to enhance std::iterator_traits so that it can automatically deduce the types difference_type, pointer and reference the way std::iterator does when they're not explicitly provided.

相关文章