std::transform 中的 [] const_iterator::value_type 是什么意思

what does [] const_iterator::value_type in std::transform mean

具体代码在这里。第 15 行在做什么(调用转换)?

谁能解释一下为什么输出 01234?另一方面,如果我在第 15 行将 cb 更改为 ++cb,它会输出 01110。第 15 行的 return 值在做什么?

#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <list>

int main()
{
    typedef std::list<int> L;
    L l(5);

    typedef L::const_iterator CI;
    CI cb = l.begin(), ce = l.end();
    typedef L::iterator I;
    I b = l.begin();
    std::transform(cb, --ce, ++b, [] (CI::value_type n) { return ++n; });
    std::copy(l.begin(), l.end(), std::ostream_iterator<CI::value_type>(std::cout));
    std::cout << std::endl;

    return 0;
}

表达式[](CI:value_type n) { return ++n; } 是一个 lambda 函数。空括号表示它不访问当前作用域的任何成员。

transform 基本上将此函数应用于输入序列 (l) 的每个元素,并将其写入输出序列 (也是 l)。由于 --ce.

而在到达最后一个元素之前的元素时停止

该代码依次获取 l 的一个元素并将其递增到 l 的下一个元素(因为 ++b)。因此你得到 0、1、2、3、4。

如果您将 cb 更改为 ++cb,您将得到 0、1、1、1、0,因为那时,您从索引为 1 的元素开始,并递增每个元素直到最后一个元素。

Find some information about lambdas here.

Explanation of std::transform

首先,您需要了解语法:方括号表示您的 lambda 函数 没有从其周围的上下文中捕获任何内容。基本上,这是在 std::transform 的调用中插入一段逻辑的简洁方法:您告诉函数转换一个值意味着向它加一个值。

为了进一步了解发生了什么,也为了解释 01110 输出,让我们看看 std::transform 做了什么:它从 cb(初始元素)向上获取项目到 --ce(从后面算起的第二个元素),包括在内,调用 lambda 函数,并将结果 returns 放入从 ++b 开始的单元格中,即索引 1、2、3等等。

第一次迭代从 L[0] 取零,加一,然后将 1 写入 L[1]。第二次迭代从之前的 1 中取出,加一,然后将 2 写入 L[2]。迭代一直持续到 std::transform4 写入 L[4].

然而,当您将 cb 替换为 ++cb 时,写入将执行到读取数据的同一单元格中,即 L[1] 被分配 0+1 ,然后 L[2] 被分配 0+1,然后 L[3] 被分配 0+1,然后循环到达 --ce,然后停止。

请注意,++n 是不必要的,因为增加 n 的副作用会在 lambda 调用结束后立即消失。您可以将其替换为 n+1 表达式,它没有副作用:

std::transform(cb, --ce, ++b, [] (CI::value_type n) { return n+1; });

在此声明中

L l(5);

创建了一个包含 5 个元素的列表,每个元素都由 0 初始化。

在本次通话中

std::transform(cb, --ce, ++b, [] (CI::value_type n) { return ++n; });

cb 指向列表的第一个元素。 --ce 求值后减量运算符指向列表的最后一个元素。 因此 cb--ce 设置列表元素的范围

[cb, --ce)

其中括号表示 --ce 不包含在范围内。

++b 计算增量后指向列表的第二个元素。 所以你有

  b 
  | 
 0 0 0 0 0
^       ^
|       |
cb      ce

cb指向的值即列表第一个元素的值在lambda表达式中增加

[] (CI::value_type n) { return ++n; }

and写在迭代器b指向的列表的第二个元素中。之后 cbb 在变换体内递增。

所以在第一次迭代之后列表看起来像

    b 
    | 
 0 1 0 0 0
  ^     ^
  |     |
  cb    ce

现在cb指向列表的第二个元素。它的值在lambda表达式中递增,写在迭代器b.

指向的第三个元素中
      b 
      | 
 0 1 2 0 0
    ^   ^
    |   |
    cb  ce

因此,您将得到该列表的值为 0、1、2、3、4。

如果你将算法的调用写成

std::transform(++cb, --ce, ++b, [] (CI::value_type n) { return ++n; });

即使用 ++cb 然后 cbb 将指向相同的元素,并且该算法将简单地从第二个元素开始用其增量值重写每个元素列表,因为使用了迭代器 ++cb。 结果将是 0, 1, 1, 1, 0