作者tinlans ( )
看板C_and_CPP
標題Re: [問題] STL for_each 算總和
時間Sat Aug 7 18:20:41 2010
→ akasan:why for_each not accumulate ? 08/07 11:29
→ loveme00835:只能用標準庫嗎? 08/07 12:41
→ loveme00835:剛剛試過boost::accumulator 似乎沒辦法疊起來用, 不 08/07 12:43
→ loveme00835:過這問題可以用transform + accumulate 兜起來, 用 08/07 12:44
→ loveme00835:lambda function 來轉整數 08/07 12:45
不知道是不是我誤會了原 po 想幹嘛?
為什麼不能用 std::accumulate?
我沒有 win32 平台的開發環境所以直接寫個小程式測試:
#include <numeric>
#include <vector>
#include <iostream>
using namespace std;
struct WIN32_FIND_DATA {
WIN32_FIND_DATA(unsigned long n) : nFileSizeLow(n) { }
unsigned long nFileSizeLow;
};
vector<WIN32_FIND_DATA> vcFind;
unsigned long fileSizeSum(unsigned long sum, const WIN32_FIND_DATA &data)
{
return sum + data.nFileSizeLow;
}
int main()
{
unsigned long sum = 0UL;
vcFind.push_back(WIN32_FIND_DATA(1));
vcFind.push_back(WIN32_FIND_DATA(2));
vcFind.push_back(WIN32_FIND_DATA(3));
sum = accumulate(vcFind.begin(), vcFind.end(), 0UL, fileSizeSum);
cout << sum << endl;
}
得到 6。
編譯器支援 lambda expression 的場合:
#include <numeric>
#include <vector>
#include <iostream>
using namespace std;
struct WIN32_FIND_DATA {
unsigned long nFileSizeLow;
WIN32_FIND_DATA(unsigned long n) : nFileSizeLow(n) { }
};
vector<WIN32_FIND_DATA> vcFind;
int main()
{
unsigned long sum = 0UL;
vcFind.push_back(WIN32_FIND_DATA(1));
vcFind.push_back(WIN32_FIND_DATA(2));
vcFind.push_back(WIN32_FIND_DATA(3));
sum = accumulate(vcFind.begin(), vcFind.end(), 0UL,
[](unsigned long sum, const WIN32_FIND_DATA &data) {
return sum + data.nFileSizeLow;
}
);
cout << sum << endl;
}
※ 引述《softwind (software everywhere)》之銘言:
[DELETE]
: like C的寫法
: unsigned long total=0;
: for(vector<WIN32_FIND_DATA>::const_iterator iter=vcFind.begin();
: iter!=vcFind.end(); iter++){
: n+=iter->nFileSizeLow;
: }
: 然後這邊可以得到該層目錄的 total file size.
: 但是 我想要套用 for_each的方式 不過想不出來正確的表示式...
: for_each(vcFind.begin(), vcFind.end(), /* 這邊該怎麼填? */ )
如果你堅持要用 for_each,
你需要一個 function object 來儲存計算結果,
再利用 for_each 的傳回值。
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
struct WIN32_FIND_DATA {
WIN32_FIND_DATA(unsigned long n) : nFileSizeLow(n) { }
unsigned long nFileSizeLow;
};
vector<WIN32_FIND_DATA> vcFind;
class FileSizeSum : public unary_function<const WIN32_FIND_DATA &, void> {
public:
FileSizeSum() : sum() { }
void operator()(const WIN32_FIND_DATA &data)
{
sum += data.nFileSizeLow;
}
unsigned long result()
{
return sum;
}
private:
unsigned long sum;
};
int main()
{
unsigned long sum = 0UL;
vcFind.push_back(WIN32_FIND_DATA(1));
vcFind.push_back(WIN32_FIND_DATA(2));
vcFind.push_back(WIN32_FIND_DATA(3));
sum = for_each(vcFind.begin(), vcFind.end(), FileSizeSum()).result();
cout << sum << endl;
}
得到 6。
編譯器支援 lambda expression 的場合:
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
struct WIN32_FIND_DATA {
WIN32_FIND_DATA(unsigned long n) : nFileSizeLow(n) { }
unsigned long nFileSizeLow;
};
vector<WIN32_FIND_DATA> vcFind;
int main()
{
unsigned long sum = 0UL;
vcFind.push_back(WIN32_FIND_DATA(1));
vcFind.push_back(WIN32_FIND_DATA(2));
vcFind.push_back(WIN32_FIND_DATA(3));
for_each(vcFind.begin(), vcFind.end(),
[&](const WIN32_FIND_DATA &data) {
sum += data.nFileSizeLow;
}
);
cout << sum << endl;
}
: 我想用 bind1st( plus<int>(), totaSize );
: 可是 WIN32_FIND_DATA 沒有辦法cast成 int...
我想這不是你要的東西。
: Ruby的話我會寫
: vcFind.each{ |find|
: totalSize+=find.dwFileSizeLow;
: }
你想這樣做的話應該是 for_each 版 + lambda expression 會適合你,
但是你的編譯器需要 C++0x 的支援。
至於到底你要取 dwFileSizeLow 還是 nFileSizeLow,
因為前後不一致所以我也無從猜測。
補充說明:
GCC 4.5.0 以上的版本支援 lambda expression,
請在編譯的時候下 -std=gnu++0x 或 -std=c++0x。
預設是 -std=gnu++98。
開頭有 gnu 才有 GNU extensions 可以用。
編這邊的 code 倒是沒什麼差異,
但是編一些 tarball 的話 gnu -> std 可能會編不過。
MS 平台我記得要 VS2010 才有吧。
: 但是轉成 C++ template...
: sorry~ 我真的是不熟 觀念上一直會卡住...
: 麻煩板上高手解答
: 感謝~
--
Ling-hua Tseng (uranus@tinlans.org)
Department of Computer Science, National Tsing-Hua University
Interesting: C++, Compiler, PL/PD, OS, VM, Large-scale software design
Researching: Software pipelining for VLIW architectures
Homepage:
http://www.tinlans.org
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 118.160.104.163
※ 編輯: tinlans 來自: 118.160.104.163 (08/07 18:39)
推 loveme00835:我想原原po應該是不想另外再寫函式或是類別 08/07 18:57
→ tinlans:那就只能去抓 VS2010 來用 lambda expression。 08/07 19:03
→ tinlans:不然堅持用 std 的東西的話,最標準最傳統的方法也是要學 08/07 19:05
→ tinlans:accumulate 已經是 Effective STL 的 Item 31 明確建議的 08/07 19:07
→ tinlans:用法了。語意跟表達上也會比較清晰。 08/07 19:07
推 loveme00835:我都用 DevC++ 寫 lambda expression XD 08/07 19:37
推 softwind:但是就算使用acc, 還是需要另外生一個class來算 08/07 23:28
→ softwind:單用 functional裡面的tempalte class, 兜不出來 08/07 23:28
→ softwind:同時 WIN32_FIND_DATA是Windows的struct 用來和 找檔案 08/07 23:30
→ softwind:的API, FindFirstFile搭配使用, 不能自訂阿 08/07 23:30
→ softwind:所以我才說 最後我想得到的作法是 想辦法在WIN32_FIND_DA 08/07 23:31
→ softwind:TA中, 注入 int cast operator,然後丟給plus<int>()中 08/07 23:32
→ loveme00835:如果要用plus<int>(), 你用一個wraper包起來就好, 再 08/07 23:36
→ loveme00835:提供operator int 來轉型 08/07 23:37
→ loveme00835:還是搞不懂寫一個程式為啥限制要那麼多= = 08/08 00:04
推 softwind:為工作而寫求安全易懂 為了練功而寫就求新求進 08/08 00:09
→ softwind:不管怎樣 感謝上面大大回文 我只是想搞清楚 純C++ 08/08 00:10
→ softwind:目前的限制而已 boost 我可能工作上很難用到 嵌入式阿 08/08 00:10
推 loveme00835:0.0 08/08 00:21
→ tinlans:用了 accumulate 只要另外生一個 function,不是 class。 08/08 01:37
→ tinlans:不過要另外寫東西才能動,是肯定的。 08/08 01:38
→ tinlans:傳進 accumulate 的如果是 function object,它本身不能做 08/08 01:39
→ tinlans:累加動作。因為標準規定那個引數的物件不能有 side-effect 08/08 01:40
→ tinlans:。如果要 function object 本身做累加,只能用 for_each。 08/08 01:40
推 hilorrk:原來是標準規定 讀Josuttis那本時我還以為只是不該這麼做 08/08 02:11
推 loveme00835:還是要有規格書在手才好查原因 ( ̄▽ ̄#)﹏﹏ 08/08 02:26
推 hilorrk:小弟是個窮大學生 印不起XD 而且還沒玩到那麼深... 08/08 02:29