需要从容器结构中的总字段数

时间:2017-07-26 14:02:37

标签: c++ stl sum containers accumulate

这更像是一个代码清晰度问题,因为我已经在这里有一个例子。我在代码中做了很多,所有这些lambda(其中一些是相同的)的创建已经开始让我感到烦恼。

所以给出了结构:

struct foo {
    int b() const { return _b; }
    int a() const { return _a; }
    int r() const { return _r; }
    const int _b;
    const int _a;
    const int _r;
};

我有一个指向它们的容器容器,让我们说vector<foo*> foos,现在我想要通过容器并得到其中一个字段的总和。
作为一个例子,如果我想要字段_r,那么我目前的方法是这样做:

accumulate(cbegin(foos), cend(foos), 0, [](const auto init, const auto i) { return init + i->r(); } )

我到处写这条线。可以对此进行任何改进吗?我真的很想写这样的东西:

x(cbegin(foos), cend(foos), mem_fn(&foo::r));

我不认为标准提供了类似的东西。我显然可以写它,但是它需要读者找出我可疑的代码,而不仅仅知道accumulate做了什么。

2 个答案:

答案 0 :(得分:1)

我建议编写一个自定义仿函数生成器,而不是编写自定义累积器,它返回一个可以用作std::accumulate参数的仿函数。

template<class Fun>
auto mem_accumulator(Fun member_function) {
    return [=](auto init, auto i) {
        return init + (i->*member_function)();
    };
}

然后

accumulate(cbegin(foos), cend(foos), 0, mem_accumulator(&foo::r));

一些变化:

对于物体的容器:

template<class MemFun>
auto mem_accumulator(MemFun member_function) {
    return [=](auto init, auto i) {
        return init + (i.*member_function)();
    };
}

使用数据成员指针而不是函数:

template<class T>
auto mem_accumulator(T member_ptr) {
    return [=](auto init, auto i) {
        return init + i->*member_ptr;
    };
}
// ...
accumulator(&foo::_r)

支持仿函数,而不是成员函数指针:

template<class Fun>
auto accumulator(Fun fun) {
    return [=](auto init, auto i) {
        return init + fun(i);
    };
}
// ...
accumulator(std::mem_fun(&foo::r))

这些变化中的一些(全部?)可能会被组合以使用一些SFINAE魔法自动选择,但这会增加复杂性。

答案 1 :(得分:1)

实际上有一种非常优雅的方法可以使用Variable Templates中引入的来解决这个问题。我们可以使用方法指针作为模板参数来模拟lambda变量:

template <int (foo::*T)()>
auto func = [](const auto init, const auto i){ return init + (i->*T)(); };

func作为func的最后一个参数的accumulate适当专门化传递给与写出lambda相同的效果:

accumulate(cbegin(foos), cend(foos), 0, func<&foo::r>)

Live Example

另一种基于相同模板化前提的替代方案,不需要,是模板化函数suggested by StoryTeller

template <int (foo::*T)()>
int func(const int init, const foo* i) { return init + (i->*T)(); }

只需传递方法指针即可使用:

accumulate(cbegin(foos), cend(foos), 0, &func<&foo::r>)

Live Example

这两个示例所需的特异性已在中删除,我们可以使用auto作为模板参数类型:http://en.cppreference.com/w/cpp/language/auto这样我们就可以声明func它可以由任何类使用,而不仅仅是foo

template <auto T>
auto func(const auto init, const auto i) { return init + (i->*T)(); }