在向量内汇总结构成员

14 c++ stl

考虑以下:

typedef struct {
    int a;
    int b;
    int c;
    int d;
} ABCD;

typedef std::vector<ABCD> VecABCD;
Run Code Online (Sandbox Code Playgroud)

假设我想在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;
}
Run Code Online (Sandbox Code Playgroud)

说我想用'b'做同样的事情?简单!我写....基本上是相同的功能,但只有微不足道的变化.与'c'和'd'相同.

那么,有没有更简洁,更少重复的方式来做到这一点?我想做点什么:

int sumOfA = SumOfMembers(myVec, a);
Run Code Online (Sandbox Code Playgroud)

但我无法想象我如何将这样的功能放在一起.理想情况下,它是一个模板,我可以使用任何类型结构的向量,而不是专门绑定到VecABCD.有人有主意吗?

Tod*_*ner 16

STL总结可以用来完成 std::accumulate

#include <functional>

accumulate(v.begin(), v.end(), 0, bind(plus<int>(), _1, bind(&ABCD::a, _2)))
Run Code Online (Sandbox Code Playgroud)

如果您希望这更通用,可以将tr1 :: function作为要绑定的成员:

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));
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用boost :: transform迭代器将逻辑放在迭代器中,而不是将逻辑放在仿函数中:

tr1::function<int (const ABCD&)> member(bind(&ABCD::a, _1));
accumulate(make_transform_iterator(v.begin(), member),
           make_transform_iterator(v.end(),   member),
           0);
Run Code Online (Sandbox Code Playgroud)

编辑添加:C++ 11 lambda语法

对于C++ 11 lambdas来说,这变得更加清晰(虽然不幸的是不会更短):

accumulate(v.begin(), v.end(), 0,
    [](int sum, const ABCD& curr) { return sum + curr.a });
Run Code Online (Sandbox Code Playgroud)

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}); });
};
Run Code Online (Sandbox Code Playgroud)

用法:

// 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; });
Run Code Online (Sandbox Code Playgroud)


Ada*_*eld 11

另一种选择是使用指向成员的指针:

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.
Run Code Online (Sandbox Code Playgroud)