常見錯誤嘗試
void print(int& a, const int b) { a += b; }
int main() {
list my_list;
// ...
for_each(my_list.begin(), my_list.end(), bind2nd(print, 3)); // 編譯失敗
}
錯誤原因分析
- bind2nd 需要仿函數,而非普通函數:
bind2nd 接受繼承自 binary_function 的仿函數物件。
- for_each 不允許修改元素:標準規定
UnaryFunction 不得透過參數執行非常數操作。
正確做法:自訂仿函數 + transform
#include
#include
#include
#include
#include
using namespace std;
// 繼承 binary_function:第一參數、第二參數、回傳型別
struct AddPrint : public binary_function {
int operator()(int a, int b) const {
cout << a + b << endl;
return a + b; // transform 需要回傳值
}
};
int main() {
vector my = {0, 1, 2};
// 1. 原始內容
copy(my.begin(), my.end(), ostream_iterator(cout, " "));
cout << "\n-----\n";
// 2. for_each 僅輸出,不修改容器
for_each(my.begin(), my.end(), bind2nd(AddPrint(), 3));
cout << "\n-----\n";
copy(my.begin(), my.end(), ostream_iterator(cout, " "));
cout << "\n-----\n";
// 3. transform 真正修改元素
transform(my.begin(), my.end(), my.begin(), bind2nd(AddPrint(), 3));
cout << "\n-----\n";
copy(my.begin(), my.end(), ostream_iterator(cout, " "));
cout << endl;
return 0;
}
輸出結果
0 1 2
-----
3
4
5
-----
0 1 2
-----
3
4
5
-----
3 4 5
關鍵點總結
| 算法 | 用途 | 是否修改容器 | 仿函數需求 |
for_each | 遍歷副作用 (列印、記錄) | 否 (標準禁止) | unary_function 或可呼叫物件 |
transform | 元素轉換並寫回 | 是 | unary_function 或 binary_function (搭配 bind2nd) |
現代 C++ (C++11+) 寫法
// Lambda 取代 bind2nd + 仿函數結構
transform(v.begin(), v.end(), v.begin(), [](int x){ return x + 3; });
for_each(v.begin(), v.end(), [](int x){ cout << x << ' '; });
// 範圍-based for (C++11)
for (auto& x : v) x += 3;
避坑指南
bind2nd / bind1st 已在 C++11 棄用,C++17 移除,請改用 std::bind 或 Lambda。
for_each 回傳傳入的仿函數副本 (C++11 前) 或引用 (C++11 起),可用於累積狀態。
- 若需修改容器元素,務必使用 transform 或直接迴圈。