std :: transform中的一元运算符

时间:2015-06-08 17:24:38

标签: c++ algorithm stl

有人可以帮助解释这行代码是如何工作的吗? 我不明白运算符在transform()中是如何工作的。 谢谢!

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));

4 个答案:

答案 0 :(得分:1)

该行

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

表示:

  1. 递减ce,递增b

  2. 对于从cb开始到ce结束的每个值(非包含!),请从b开始放置一个递增的值。

    < / LI>

答案 1 :(得分:1)

绘制图片可能会有所帮助。这一行:

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

可以改写为:

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

其中:

0 --> 0 --> 0 --> 0 --> 0 --> {null}
↑     ↑                 ↑
cb    b                 ce

循环的每一步都将*b设置为f(*cb) == *cb + 1,并递增两个迭代器。因此,经过一步之后我们就会:

0 --> 1 --> 0 --> 0 --> 0 --> {null}
      ↑     ↑           ↑
      cb    b           ce

第二次之后:

0 --> 1 --> 2 --> 0 --> 0 --> {null}
            ↑     ↑     ↑
            cb    b     ce

答案 2 :(得分:1)

该列表有5个由零初始化的元素:

L l(5);

你可以想象他们喜欢

{ 0, 0, 0, 0, 0 }

迭代器对cb, - em设置列表的以下元素范围

{ 0, 0, 0, 0, 0 }
  ^          ^
  |__________|
  cb        --ce

由于ce:--ce的减少,列表的最后一个元素未包含在列表中。 这是第一个迭代器指向列表的第一个元素,第二个迭代器指向列表的最后一个元素。

Iterator ++ b设置范围的开头

    ++b
     |          |          
{ 0, 0, 0, 0, 0 }
  ^          ^
  |__________|
  cb        --ce

该算法以下列方式工作。在第一次迭代中,cb指向的值增加并存储在iterator ++ b指向的元素中

    ++b
     |          |          
{ 0, 1, 0, 0, 0 }
  ^          ^
  |__________|
  cb        --ce

然后迭代器向右移动。

       ++b
        |       |          
{ 0, 1, 0, 0, 0 }
     ^       ^
     |_______|
     cb     --ce

然后重复该操作:迭代器cb指向的元素中的值增加并存储在iterator ++ b指向的元素中,你得到

       ++b
        |       |          
{ 0, 1, 2, 0, 0 }
     ^       ^
     |_______|
     cb     --ce

然后迭代器再次向右移动

          ++b
           |    |          
{ 0, 1, 2, 0, 0 }
        ^    ^
        |____|
        cb  --ce

等等。

使用标头std::iota中声明的标准算法<numeric>可以更简单明了地完成此操作。例如

#include <numeric>

//...

std::iota( l.begin(), l.end(), 0 );

这是一个展示两种方法的示范程序

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

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

    for ( int x : l ) std::cout << x << ' ';
    std::cout << std::endl;

    std::transform( l.begin(), std::prev( l.end() ), std::next( l.begin() ),
                    []( int x ) { return ++x; } );

    for ( int x : l ) std::cout << x << ' ';
    std::cout << std::endl;

    std::cout << std::endl;

    l.assign( 5, 0 );

    for ( int x : l ) std::cout << x << ' ';
    std::cout << std::endl;

    std::iota( l.begin(), l.end(), 0 );

    for ( int x : l ) std::cout << x << ' ';
    std::cout << std::endl;

    return 0;
}

程序输出

0 0 0 0 0 
0 1 2 3 4 

0 0 0 0 0 
0 1 2 3 4 

如果您的编译器支持C ++ 2014,那么您也可以采用以下方式:)

l.assign( 5, 0 );

for ( int x : l ) std::cout << x << ' ';
std::cout << std::endl;

std::generate( l.begin(), l.end(), [value = 0]() mutable { return value++; } );

for ( int x : l ) std::cout << x << ' ';
std::cout << std::endl;

输出与上面相同。

答案 3 :(得分:1)

论点nr。 4是lambda expression,您可以选择拥有自己的变换函数。这个:[] (CI::value_type n) { return ++n; }的作用是:

由于它是一元操作,你可以有一个参数,上面的lambda有一个参数。 (transform允许您也通过两个参数进行二进制运算) 函数transformcb to --ce范围内的每个元素调用上面的lambda。

CI::value_type nint,因此transform会调用传递int的函数,并在返回之前递增它,将结果存储在从++b开始的范围内。

例如,使用函数代替使用lambda也可以工作:

int inc(int n)
{
    return ++n;
}
std::transform(cb, --ce, ++b, inc);

此外,对我来说这样做更有意义:

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

遍历范围中的每个值,递增值。 这是DEMO