Consider the following:
typedef struct {
int a;
int b;
int c;
int d;
} ABCD;
typedef std::vector VecABCD;
Say
You could use for_each. Its an option.
#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;
}
output:
4
STL summations can be done with std::accumulate
#include <functional>
accumulate(v.begin(), v.end(), 0, bind(plus<int>(), _1, bind(&ABCD::a, _2)))
If you wanted this to be more generic, you could take a tr1::function to the member you want to bind:
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));
Another way to do it, rather than putting your logic in the functor, would be to put the logic in the iterator, using a 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);
EDITED TO ADD: C++11 lambda syntax
This becomes somewhat clearer with the C++11 lambdas (though unfortunately not shorter):
accumulate(v.begin(), v.end(), 0,
[](int sum, const ABCD& curr) { return sum + curr.a });
and
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}); });
};
Usage:
// 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; });
Another option would be to use pointer-to-members:
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.
Use std::accumulate :)
Let's add one more option, unfortunately an ugly one. It's possible to take the relative address from start of the struct ABCD to it's member by offsetof -function. Deliver return value to function and it can do counting using relative location from the start of each struct. If your types may differ from int, you may want to deliver also the sizeof information.