시리즈: C++
cpp
371 줄
· 업데이트 2026-04-03
std_function.cpp
C++/Part3_泛型與STL/Ch15_Lambda與函式物件/std_function.cpp
// Ch15 — std::function 示範
// 編譯:g++ -std=c++17 -Wall -o std_function std_function.cpp
#include <iostream>
#include <functional> // std::function
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include <iomanip>
#include <cmath>
// 輔助函式:印出分隔線
void section(const std::string& title) {
std::cout << "\n===== " << title << " =====\n";
}
// ============================================================
// 普通函式(用來示範 std::function 儲存普通函式)
// ============================================================
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
double squareRoot(double x) { return std::sqrt(x); }
// ============================================================
// 函式物件(用來示範 std::function 儲存函式物件)
// ============================================================
class Multiplier {
int factor_;
public:
explicit Multiplier(int factor) : factor_(factor) {}
int operator()(int x) const { return x * factor_; }
};
// ============================================================
// 事件處理器類別
// ============================================================
class EventSystem {
// 儲存事件名稱對應的回呼函式列表
std::map<std::string, std::vector<std::function<void(const std::string&)>>> handlers_;
public:
// 註冊事件處理器
void on(const std::string& event,
std::function<void(const std::string&)> handler) {
handlers_[event].push_back(std::move(handler));
}
// 觸發事件
void emit(const std::string& event, const std::string& data = "") {
auto it = handlers_.find(event);
if (it != handlers_.end()) {
std::cout << "[事件觸發] " << event << "\n";
for (const auto& handler : it->second) {
handler(data);
}
} else {
std::cout << "[事件觸發] " << event << "(無處理器)\n";
}
}
};
// ============================================================
// 簡易計算機類別
// ============================================================
class Calculator {
std::map<std::string, std::function<double(double, double)>> operations_;
std::vector<std::string> history_;
public:
Calculator() {
operations_["+"] = [](double a, double b) { return a + b; };
operations_["-"] = [](double a, double b) { return a - b; };
operations_["*"] = [](double a, double b) { return a * b; };
operations_["/"] = [](double a, double b) {
if (b == 0) throw std::runtime_error("除以零");
return a / b;
};
operations_["^"] = [](double a, double b) { return std::pow(a, b); };
operations_["%"] = [](double a, double b) {
return std::fmod(a, b);
};
}
// 新增自訂運算
void addOperation(const std::string& name,
std::function<double(double, double)> op) {
operations_[name] = std::move(op);
}
double calculate(const std::string& op, double a, double b) {
auto it = operations_.find(op);
if (it == operations_.end()) {
throw std::runtime_error("未知運算:" + op);
}
double result = it->second(a, b);
history_.push_back(std::to_string(a) + " " + op + " "
+ std::to_string(b) + " = " + std::to_string(result));
return result;
}
void printHistory() const {
std::cout << "計算歷史:\n";
for (const auto& entry : history_) {
std::cout << " " << entry << "\n";
}
}
void listOperations() const {
std::cout << "支援的運算:";
for (const auto& [name, _] : operations_) {
std::cout << name << " ";
}
std::cout << "\n";
}
};
int main() {
// ========================================================
// 1. std::function 基本用法
// ========================================================
section("1. std::function 基本用法");
// 儲存 lambda
std::function<int(int, int)> op = [](int a, int b) { return a + b; };
std::cout << "Lambda 加法:" << op(3, 4) << "\n";
// 儲存普通函式
op = add;
std::cout << "普通函式 add:" << op(3, 4) << "\n";
op = subtract;
std::cout << "普通函式 subtract:" << op(10, 3) << "\n";
// 儲存函式物件
std::function<int(int)> triple = Multiplier(3);
std::cout << "函式物件 Multiplier(3):" << triple(7) << "\n";
// 檢查 std::function 是否有效
std::function<void()> empty;
std::cout << "empty 是否有效:" << (empty ? "是" : "否") << "\n";
empty = []() { std::cout << "現在有效了!\n"; };
std::cout << "賦值後是否有效:" << (empty ? "是" : "否") << "\n";
empty();
// ========================================================
// 2. std::function 作為函式參數(callback)
// ========================================================
section("2. std::function 作為 callback");
// 對 vector 的每個元素套用轉換,並印出結果
auto applyAndPrint = [](const std::vector<int>& v,
std::function<int(int)> func,
const std::string& desc) {
std::cout << desc << ":";
for (int x : v) {
std::cout << func(x) << " ";
}
std::cout << "\n";
};
std::vector<int> nums = {1, 2, 3, 4, 5};
applyAndPrint(nums, [](int x) { return x * x; }, "平方");
applyAndPrint(nums, [](int x) { return x * 2; }, "雙倍");
applyAndPrint(nums, [](int x) { return x + 100; }, "加 100");
applyAndPrint(nums, Multiplier(5), "乘 5");
// 接受二元函式的高階函式
auto reduce = [](const std::vector<int>& v, int init,
std::function<int(int, int)> op) -> int {
int result = init;
for (int x : v) {
result = op(result, x);
}
return result;
};
std::cout << "加法 reduce:" << reduce(nums, 0, add) << "\n";
std::cout << "乘法 reduce:" << reduce(nums, 1, multiply) << "\n";
std::cout << "最大值 reduce:" << reduce(nums, nums[0],
[](int a, int b) { return std::max(a, b); }) << "\n";
// ========================================================
// 3. std::function 在容器中
// ========================================================
section("3. std::function 在容器中");
// map:運算名稱 → 函式
std::map<std::string, std::function<double(double, double)>> mathOps = {
{"加法", [](double a, double b) { return a + b; }},
{"減法", [](double a, double b) { return a - b; }},
{"乘法", [](double a, double b) { return a * b; }},
{"除法", [](double a, double b) { return b != 0 ? a / b : 0; }},
{"次方", [](double a, double b) { return std::pow(a, b); }}
};
double x = 10.0, y = 3.0;
std::cout << "x = " << x << ", y = " << y << "\n";
for (const auto& [name, func] : mathOps) {
std::cout << " " << name << ":" << std::fixed
<< std::setprecision(2) << func(x, y) << "\n";
}
// vector:儲存一系列轉換函式
std::vector<std::function<double(double)>> pipeline = {
[](double x) { return x * 2; }, // 乘 2
[](double x) { return x + 10; }, // 加 10
[](double x) { return std::sqrt(x); }, // 開根號
[](double x) { return std::round(x * 100) / 100; } // 取到小數第二位
};
double val = 8.0;
std::cout << "\n管線處理:起始值 = " << val << "\n";
for (size_t i = 0; i < pipeline.size(); i++) {
val = pipeline[i](val);
std::cout << " 步驟 " << (i + 1) << ":" << val << "\n";
}
// ========================================================
// 4. 事件處理器模式
// ========================================================
section("4. 事件處理器模式");
EventSystem events;
// 註冊多個處理器
events.on("click", [](const std::string& data) {
std::cout << " 處理器 A:收到點擊事件,資料 = " << data << "\n";
});
events.on("click", [](const std::string& data) {
std::cout << " 處理器 B:記錄點擊事件到日誌\n";
});
events.on("submit", [](const std::string& data) {
std::cout << " 表單提交處理:" << data << "\n";
});
events.on("submit", [](const std::string& data) {
std::cout << " 驗證資料:" << data << "\n";
});
events.on("error", [](const std::string& data) {
std::cout << " *** 錯誤處理:" << data << " ***\n";
});
// 觸發事件
events.emit("click", "按鈕 A");
std::cout << "\n";
events.emit("submit", "使用者表單");
std::cout << "\n";
events.emit("error", "網路連線逾時");
std::cout << "\n";
events.emit("unknown");
// ========================================================
// 5. 計算機範例
// ========================================================
section("5. 可擴充計算機");
Calculator calc;
calc.listOperations();
std::cout << "10 + 3 = " << calc.calculate("+", 10, 3) << "\n";
std::cout << "10 - 3 = " << calc.calculate("-", 10, 3) << "\n";
std::cout << "10 * 3 = " << calc.calculate("*", 10, 3) << "\n";
std::cout << "10 / 3 = " << std::fixed << std::setprecision(4)
<< calc.calculate("/", 10, 3) << "\n";
std::cout << "2 ^ 10 = " << calc.calculate("^", 2, 10) << "\n";
// 新增自訂運算
calc.addOperation("max", [](double a, double b) {
return std::max(a, b);
});
calc.addOperation("min", [](double a, double b) {
return std::min(a, b);
});
std::cout << "max(7, 3) = " << calc.calculate("max", 7, 3) << "\n";
std::cout << "min(7, 3) = " << calc.calculate("min", 7, 3) << "\n";
std::cout << "\n";
calc.printHistory();
// ========================================================
// 6. std::function 與策略模式
// ========================================================
section("6. 策略模式(Strategy Pattern)");
// 不同的折扣策略
using DiscountStrategy = std::function<double(double)>;
DiscountStrategy noDiscount = [](double price) {
return price;
};
DiscountStrategy percentOff = [](double price) {
return price * 0.8; // 八折
};
DiscountStrategy fixedOff = [](double price) {
return std::max(0.0, price - 50.0); // 減 50 元
};
DiscountStrategy memberDiscount = [](double price) {
if (price >= 500) return price * 0.7; // 滿 500 打七折
if (price >= 200) return price * 0.85; // 滿 200 打八五折
return price * 0.95; // 基本九五折
};
// 計算各策略下的價格
std::map<std::string, DiscountStrategy> strategies = {
{"無折扣", noDiscount},
{"八折", percentOff},
{"減 50 元", fixedOff},
{"會員折扣", memberDiscount}
};
std::vector<double> testPrices = {100, 250, 500, 1000};
std::cout << std::setw(12) << "原價";
for (const auto& [name, _] : strategies) {
std::cout << std::setw(12) << name;
}
std::cout << "\n" << std::string(60, '-') << "\n";
for (double price : testPrices) {
std::cout << std::setw(10) << std::fixed << std::setprecision(0)
<< "$" << price;
for (const auto& [_, strategy] : strategies) {
std::cout << std::setw(10) << "$"
<< std::setprecision(0) << strategy(price);
}
std::cout << "\n";
}
// ========================================================
// 7. 函式組合
// ========================================================
section("7. 函式組合(compose)");
// compose(f, g) 回傳一個函式 h(x) = f(g(x))
auto compose = [](std::function<double(double)> f,
std::function<double(double)> g) {
return [f, g](double x) -> double {
return f(g(x));
};
};
std::function<double(double)> doubleIt = [](double x) { return x * 2; };
std::function<double(double)> addTen = [](double x) { return x + 10; };
std::function<double(double)> sqrtIt = squareRoot;
// 組合:先乘2,再加10
auto doubleThenAdd = compose(addTen, doubleIt);
std::cout << "doubleThenAdd(5) = (5*2)+10 = " << doubleThenAdd(5) << "\n";
// 組合:先加10,再乘2
auto addThenDouble = compose(doubleIt, addTen);
std::cout << "addThenDouble(5) = (5+10)*2 = " << addThenDouble(5) << "\n";
// 三層組合:先乘2,再加10,最後開根號
auto combined = compose(sqrtIt, compose(addTen, doubleIt));
std::cout << "combined(8) = sqrt((8*2)+10) = sqrt(26) ≈ "
<< std::setprecision(4) << combined(8) << "\n";
return 0;
}
관련 글
C++
c
업데이트 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/deviceAlpha.h).
글 읽기 →
C++
c
업데이트 2026-07-21
finalproject.c
finalproject.c — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.c).
글 읽기 →
C++
cpp
업데이트 2026-07-21
finalproject.cpp
finalproject.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.cpp).
글 읽기 →
C++
c
업데이트 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/deviceAlpha.h).
글 읽기 →
C++
c
업데이트 2026-07-21
lab8.c
lab8.c — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.c).
글 읽기 →
C++
cpp
업데이트 2026-07-21
lab8.cpp
lab8.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.cpp).
글 읽기 →