如何优雅地修改容器中的所有元素?

时间:2016-01-19 06:39:30

标签: c++ algorithm c++11 stl containers

#include <vector>

using namespace std;

class A
{
public:
    A() = default;

    void Add()
    {
        a++;
    }

private:
    int a;
};

int main()
{
    vector<A> x(10);
    for (auto pos = x.begin(); pos != x.end(); ++pos) pos->Add();
}

for_each似乎没有修改。 http://en.cppreference.com/w/cpp/algorithm/for_each

  

f - 要应用于解除引用结果的函数对象   [first,last]范围内的每个迭代器

     

该功能的签名应与以下内容相同:

     

虚无趣(const Type&amp; a);

     

签名不需要const&amp ;. Type类型必须是   这样可以取消引用InputIt类型的对象   隐式转换为Type。

所以,我的问题是:

是否有与for (auto pos = x.begin(); pos != x.end(); ++pos) pos->Add();相同的标准功能/方法?

4 个答案:

答案 0 :(得分:5)

不确定你为什么写那个

  

for_each是非修改

这很好用:

for_each(begin(x), end(x), [](int &i){++i;});  

表示vector个整数,例如

答案 1 :(得分:4)

您可以使用

for(auto& p : x) p.Add();

这段代码简单而优雅,但也非常高效,因为它允许编译器直接查看操作而无需插入额外的逻辑。打字错误,打字速度更快,在制作拼写错误时没有胡言请语。

例如g ++为

生成的代码
for (auto& y : x) {
    y++;
}

其中x被声明为std::vector<int>有一个内部循环,如

.L8:
    movdqa  (%rdi,%rax), %xmm0
    addq    $1, %rdx
    paddd   %xmm1, %xmm0
    movaps  %xmm0, (%rdi,%rax)
    addq    $16, %rax
    cmpq    %rdx, %r8
    ja  .L8

其中使用mmx指令在每次迭代时递增4个整数。

答案 2 :(得分:2)

#imagens:before, #videos:before { position: absolute; width: 100%; height: 100%; left: 0; top: 0; content: ""; transition: all .5s ease; -webkit-transition: all .5s ease; filter: blur(0); -webkit-filter: blur(0); } #imagens:hover:before, #videos:hover:before { filter: blur(2px); -webkit-filter: blur(2px); } #imagens:before { background-image: url("http://gamerealla.ru/wp-content/uploads/2014/09/1392986721_r1.jpg"); background-position: right center; } #videos:before { background-image: url("http://gamehall.uol.com.br/v10/wp-content/uploads/2015/01/Black-Desert-Online-Beast-Master-Woman-02.jpg"); background-position: left center; } 正是你在寻找什么:

std::for_each

然而,6502的答案是更好的方法。

修改

关于您引用的引用。在同一页面通知中:

  

f可以通过解除引用来修改范围的元素   迭代器

答案 3 :(得分:0)

迟到的答案,但没人提到std::transform

#include <algorithm>
#include <vector>
#include <iostream>

using namespace std;

class A
{
public:
    A() = default;

    A& Add()
    {
        a++;
        return *this; // this will make it compatible with std::transform
    }

    friend std::ostream& operator<<(std::ostream& os, A const& a)
    {
        return os << a.a;     
    }
private:
    int a;
};

int main()
{
    vector<A> x(10);
    std::transform(x.begin(), x.end(), x.begin(), [](auto& elem) { 
        return elem.Add(); 
    });
    std::copy(x.begin(), x.end(), std::ostream_iterator<A>(std::cout, ","));
}

Live Example.

请注意,我必须将Add()的返回类型修改为A&。这使其与std::transform兼容,并且还模仿operator++的返回类型。

当然,带有单个语句的原始循环或for_each也可以。但transform是一种词汇算法,可立即向您的代码读者表明您正在修改容器。从原始循环和for_each开始,这需要更仔细的审查(也许这里很简单,但是在更大的代码中这些东西加起来)。请注意

之间的区别
    std::transform(x.begin(), x.end(), x.begin(), [](auto& elem) { 
        // many lines but x will always be written to
    });

    std::for_each(x.begin(), x.end(), [](auto& elem) { 
        // many lines, will always need to inspect the code here 
        // to know if `elem` is actually being written to
        // the `auto&` is only a hint that this might happen
    });