2017-07-26 50 views
1

这是更多的代码clenliness问题,因为我已经有一个例子在这里。我在代码中做了这么多,所有这些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是干什么的。

+0

我没有看到一个问题,提供了一个小工具功能。有时候人们也必须去查找关于标准库中的东西的信息。很少有人知道这一切。只要它是干净的,可访问的,为什么不在标准库中添加一个抽象? – StoryTeller

+0

@StoryTeller现在我也倾向于这一点。这个问题是我去做之前的最后一站,只是觉得应该有更好的方法。 –

+1

您是否考虑过类方法:“static void foo :: acc4(std :: vector foos)”在一次执行中执行所有4次累加? –

回答

1

实际上有一个非常优雅的方法来解决这个问题,使用Variable Templates这是在介绍。

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

传递的funcfunc适当专业化为最后一个参数accumulate将在地方写出来的拉姆达同样的效果:我们可以使用方法指针作为模板参数模板化一λ变量

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)(); } 
+0

@StoryTeller这个概念似乎有道理。我甚至开始更新我的答案,但由于某种原因,我无法将模板化函数的地址传递给'accumulate':http://ideone.com/WTfxQR我很确定这是合法的:https:// stackoverflow。 com/q/38402133/2642059我在这里做错了什么? –

+1

[您错过了指向成员的const限定符](http://ideone.com/FhrIlc)。我删除了我的帖子,因为C++ 98解决方案不如通用lambda强壮(正如您的示例通过命名类型所示)。 – StoryTeller

+0

@StoryTeller谢谢,我知道我错过了一些东西。 C++ 17让我们更进一步,防止我犯这样的错误:'template auto func(const auto init,const auto i){return init +(i - > * T)(); }' –

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魔术自动选择,但是这会增加复杂性。

相关问题