【问题标题】:Why do std::generate() and std::generate_n() require different iterators?为什么 std::generate() 和 std::generate_n() 需要不同的迭代器?
【发布时间】:2017-07-22 11:44:53
【问题描述】:

我在 cppreference 中查看generate()generate_n() 并试图理解为什么generate() 需要ForwardIterator,而generate_n() 需要OutputIterator 的范围? (我查了最新的标准工作草案,也是一样的要求。)

因为,至少它们可能的实现似乎需要相同的迭代器概念,而OutputIterator 似乎就足够了:

generate():

template<class ForwardIt, class Generator>
void generate(ForwardIt first, ForwardIt last, Generator g)
{
    while (first != last) {
        *first++ = g();
    }
}

generate_n():

template<class OutputIt, class Size, class Generator>
OutputIt generate_n(OutputIt first, Size count, Generator g)
{
    for (Size i = 0; i < count; i++) {
        *first++ = g();
    }
    return first;
}

std::fill()std::fill_n() 也是如此。

【问题讨论】:

    标签: c++ iterator language-lawyer


    【解决方案1】:

    至少它们可能的实现似乎需要相同的迭代器概念,OutputIterator 似乎就足够了

    OutputIterator 不支持相等/不等比较(包括您展示的generate() 的可能实现中使用的operator!=)和多通道保证,而ForwardIterator 支持。这意味着OutputIterator 不能用于通过generate() 的接口所需的两个迭代器(例如[first, last))来表示范围。

    不能为输出迭代器定义等式和不等式。即使定义了 operator==,x == y 也不必暗示 ++x == ++y。

    【讨论】:

      【解决方案2】:

      songyuanyao's answer 从技术角度解释这个问题。我将尝试提供更非正式的解释。

      许多 STL 算法,包括 generatefill,都适用于许多项目。算法必须能够访问这些项目的方式定义了迭代器的要求。

      在您的情况下,generate 的定义包含:

      ...
      while (first != last) {  // implies that Iter implements operator!=
        *first++;              // implies that Iter implements operator++
      

      虽然任何迭代器类型似乎都满足第二个要求(毕竟,这就是迭代器的全部意义——迭代事物:)),但并非所有迭代器类型都支持比较operator!=

      例如,您不能将ostream_iterator 用于std::generate。但是,您可以,例如,通过std::generate_n 将固定数量的生成值输出到流中。

      这里是a very artificial example at Coliru。一旦我开始考虑现实生活中的应用程序,我猜想使用 OutputIterators 的能力可能对实现一些序列化逻辑很有用。

      【讨论】:

        【解决方案3】:

        generate()generate_n() 与所有标准库算法一样,对范围 进行操作,即通过迭代器访问的一系列值。为了将操作应用于范围的所有元素,算法必须知道范围的开始位置和结束位置。有两种常见的方式来提供该信息:您可以使用迭代器和长度指定范围,并使用while (length-- != 0) { ... ++first; } 形式的循环;或者您可以使用一对迭代器[first, last) 指定范围,并使用while (first != last) { ... ++first; } 形式的循环。

        对于第一个版本,您需要能够递增迭代器,并且对于这些算法,通过迭代器写入一个值。这些是输出迭代器的主要属性,这就是generate_n()所需要的全部。

        对于第二个版本,您需要能够增加迭代器并通过迭代器写入一个值,就像第一个版本一样。您必须能够比较两个迭代器是否相等,而输出迭代器不支持这一点;你必须至少有一个前向迭代器。这就是为什么 generate() 需要一个由一对迭代器指定的范围,需要一个前向迭代器。

        【讨论】:

          猜你喜欢
          • 2017-02-19
          • 2021-01-16
          • 2011-07-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-03
          • 2016-09-07
          • 2016-04-16
          相关资源
          最近更新 更多