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

How to elegantly modify all elements in a container in-place?

#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 - function object, to be applied to the result of dereferencing every iterator in the range [first, last)

The signature of the function should be equivalent to the following:

void fun(const Type &a);

The signature does not need to have const &. The type Type must be such that an object of type InputIt can be dereferenced and then implicitly converted to Type.

那么,我的问题是:

是否有一个标准 function/way 可以像 for (auto pos = x.begin(); pos != x.end(); ++pos) pos->Add(); 那样做?

你可以使用

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

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

例如g++为

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

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

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

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

不确定为什么要这样写

for_each is non-modifying

这很好用:

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

对于 vector 个整数,例如

std::for_each 正是您要找的东西:

std::for_each(std::begin(x),std::end(x),[](A& item){item.add();});

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

编辑:

关于您引用的报价。在同页通知:

f may modify the elements of the range through the dereferenced iterator

迟到的回答,但没有人提到 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() 的 return 类型修改为 A&。这使得它与 std::transform 兼容,并且还模仿 operator++ 的 return 类型。

当然,只有一个语句的 raw-loop 或 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
    });