【问题标题】:How to tell advance() to use += operator on input iterators if they aren't random access如果输入迭代器不是随机访问,如何告诉Advance()在输入迭代器上使用+=运算符
【发布时间】:2013-05-21 06:30:58
【问题描述】:

考虑像join_iterator 这样的输入迭代器:它迭代其他范围的串联。重复调用++i 可能比简单的i += n很多

尽管如此,大多数需要将迭代器推进任意数量的 C++ 代码都使用 std::advance,当迭代器不是随机访问时,它会自动调用 ++i

(遗憾的是,大多数人使用std::advance(i, n) 而不是using std::advance; advance(i, n),所以我不能只为我的迭代器提供advance 并依赖ADL。)

另一方面,我不能使用++=,因为输入迭代器不必实现它们。

所以问题是:我将如何支持这样的场景,什么时候:

  • 实现这样的迭代器?

  • 使用可能具有优化的operator +=的输入迭代器?

(请注意,advance+ 并不是唯一重要的场景——distance- 也有同样的问题。)

【问题讨论】:

  • @MichaelAaronSafyan:嗯,是因为大家好像都用std::advance而不是advance,所以就算我提供了,也不会实际使用。
  • @MichaelAaronSafyan:是的,我确实需要这种快速迭代。 (是的,我实际上知道 ++ is 太慢了。)我自己也遇到过both 的情况——自己编写迭代器,以及编写将从这种优化的迭代器中受益的算法。我想知道如何正确处理 both 情况:即如何provideconsume 这样的迭代器。
  • @Mehrdad 没错,但我们会专门化一个模板,而不是重载一个函数(我认为)。参照。 stackoverflow.com/a/14403772/777186
  • @jogojapan:啊,部分函数特化虽然适用于 C++11,但大多数迭代器都是模板化的,因此它们需要部分特化而不是完全特化,对吧?我会对 C++03 做什么?
  • @Mehrdad 你是对的。我的解决方案只有在您对两个模板参数都专门化 std::advance 时才有效,即明确专门化它。这不好,因为您不能(或不想)预期第二个参数的所有可能整数类型。

标签: c++ iterator


【解决方案1】:

根据 C++11 §24.4.4,

由于只有随机访问迭代器提供 + 和 - 运算符,因此库提供了两个函数模板 advancedistance这些函数模板将+- 用于随机访问迭代器(因此它们的时间是常数); 对于输入、前向和双向迭代器,它们使用++ 来提供线性时间实现.

您应该只需要定义+-,并指定std::random_access_iterator_tag。无需专门化或重载std::advance

【讨论】:

  • 那是在撒谎——迭代器不是随机访问的。
  • 嗯?我在哪里说恒定时间? o_O
  • @Mehrdad 啊,我明白了。尽管如此,如果有任何潜在的收益,一些潜在的子范围必须是随机访问的。我建议简单地撒谎。复杂性保证在数学上是违反的,但这是让客户端代码注意“随机访问”运算符的唯一方法。
  • 撒谎的问题在于,它会造成附带损害!例如,使其随机访问也需要我实现operator--——但我通常不能。这意味着对于随机访问迭代器具有不同(例如优化)行为的任何现有代码(可能通过使用带有否定参数的 operator-=operator+=)现在完全无法与我的迭代器一起使用......并且以免您认为这有点牵强,Visual C++ 对 std::rotate 使用不同的算法,具体取决于迭代器是否为随机访问。
  • @Mehrdad 真不幸……我个人在 2009 年重写了 GCC 的 (libstdc++-v3) std::rotate,因为随机访问风格普遍比只进风格慢。下一个更好的撒谎方法是派生或代理迭代器将随机访问标签添加到“真实”类,因此可以明智地应用黑客攻击。我想不出没有性能和存储损失的其他解决方案。
猜你喜欢
  • 2022-11-14
  • 2011-07-09
  • 2011-05-17
  • 2017-10-15
  • 2017-09-02
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多