如何优雅地就地修改容器中的所有元素?
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, ","));
}
请注意,我必须将您的 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
});
#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, ","));
}
请注意,我必须将您的 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
});