2017-07-26 48 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魔術自動選擇,但是這會增加複雜性。

相關問題