请考虑以下事项:
typedef struct {
int a;
int b;
int c;
int d;
} ABCD;
typedef std::vector<ABCD> VecABCD;
假设我想在VecABCD类型的向量中添加每个'a'成员。简单!我只是循环遍历向量,并在我去的时候求和。
int CalcSumOfA(const VecABCD &vec)
{
int sumOfA = 0;
VecABCD::const_iterator it;
for(it=vec.begin();it!=vec.end();it++)
sumOfA += it->a;
return sumOfA;
}
说我想用'b'做同样的事情?简单!我写....基本上是相同的功能,但只有微不足道的变化。与'c'和'd'相同。
那么,是否有更简洁,更少重复的方式来做到这一点?我想做点什么:
int sumOfA = SumOfMembers(myVec, a);
但我无法想象我如何将这样的功能放在一起。理想情况下,它是一个模板,我可以使用任何类型结构的向量,而不是专门绑定到VecABCD。有人有什么想法吗?
答案 0 :(得分:14)
STL摘要可以使用std::accumulate
#include <functional>
accumulate(v.begin(), v.end(), 0, bind(plus<int>(), _1, bind(&ABCD::a, _2)))
如果您希望这更通用,可以将tr1 ::函数带到要绑定的成员:
int sum_over_vec(const vector<ABCD>& v, const tr1::function<int (const ABCD&)>& member)
{
return accumulate(v.begin(), v.end(),
0,
bind(plus<int>(),
_1,
bind(member, _2)));
};
// ...
int sum_a = sum_over_vec(vec, bind(&ABCD::a, _1));
另一种方法,而不是将你的逻辑放在仿函数中,就是使用boost :: transform iterator将逻辑放在迭代器中:
tr1::function<int (const ABCD&)> member(bind(&ABCD::a, _1));
accumulate(make_transform_iterator(v.begin(), member),
make_transform_iterator(v.end(), member),
0);
编辑添加:C ++ 11 lambda语法
对于C ++ 11 lambdas来说,这会变得更加清晰(虽然不幸的是不会更短):
accumulate(v.begin(), v.end(), 0,
[](int sum, const ABCD& curr) { return sum + curr.a });
和
int sum_over_vec(const vector<ABCD>& v, const std::function<int (const ABCD&)>& member)
{
return accumulate(v.begin(), v.end(), 0,
[&](int sum, const ABCD& curr) { return sum + member(curr}); });
};
用法:
// Use a conversion from member function ptr to std::function.
int sum_a = sum_over_vec(vec, &ABCD::a);
// Or using a custom lambda sum the squares.
int sum_a_squared = sum_over_vec(vec,
[](const ABCD& curr) { return curr.a * curr.a; });
答案 1 :(得分:10)
另一种选择是使用指向成员的指针:
int CalcSumOf(const VecABCD & vec, int ABCD::*member)
{
int sum = 0;
for(VecABCD::const_iterator it = vec.begin(), end = vec.end(); it != end; ++it)
sum += (*it).*member;
return sum;
}
...
int sumA = CalcSumOf(myVec, &ABCD::a); // find sum of .a members
int sumB = CalcSumOf(myVec, &ABCD::b); // find sum of .b members
// etc.
答案 2 :(得分:1)
您可以使用for_each。这是一个选择。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef struct{
int a;
}ABCD;
typedef vector<ABCD> vecABCD;
struct sum : public unary_function<ABCD, void>
{
sum(){count.a=count.b=count.c=count.d=0;}
void operator() (ABCD x) {
count.a+=x.a;
count.b+=x.b;
count.c+=x.c;
count.d+=x.d;
}
ABCD count;
};
int main()
{
ABCD s1={1,2,3,4};
ABCD s2={5,6,7,8};
vecABCD v;
v.push_back(s1);
v.push_back(s2);
sum s = for_each(v.begin(), v.end(), sum());
cout<<s.count.a<<endl;
}
输出:
4
答案 3 :(得分:1)
使用std::accumulate:)
答案 4 :(得分:0)
让我们再添加一个选项,遗憾的是一个丑陋的选项。可以通过offsetof -function从struct ABCD的开头到它的成员获取相对地址。将返回值传递给函数,它可以使用每个结构开头的相对位置进行计数。如果您的类型可能与int不同,您可能还希望提供sizeof信息。