S SmartDocs
Serie: C++ cpp 348 líneas · Actualizado 2026-04-03

lambda.cpp

C++/Part3_泛型與STL/Ch15_Lambda與函式物件/lambda.cpp

// Ch15 — Lambda 表達式示範
// 編譯:g++ -std=c++17 -Wall -o lambda lambda.cpp

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <string>
#include <iomanip>

// 輔助函式:印出分隔線
void section(const std::string& title) {
    std::cout << "\n===== " << title << " =====\n";
}

// 輔助函式:印出 vector 內容
template<typename T>
void printVec(const std::string& label, const std::vector<T>& v) {
    std::cout << label;
    for (const auto& x : v) std::cout << x << " ";
    std::cout << "\n";
}

int main() {
    // ========================================================
    // 1. Lambda 基本語法
    // ========================================================
    section("1. Lambda 基本語法");

    // 最簡單的 lambda:無參數、無捕獲
    auto greet = []() {
        std::cout << "你好,這是一個 Lambda!\n";
    };
    greet();

    // 帶參數的 lambda
    auto add = [](int a, int b) {
        return a + b;
    };
    std::cout << "3 + 4 = " << add(3, 4) << "\n";

    // 明確指定回傳型別
    auto safeDivide = [](double a, double b) -> double {
        if (b == 0.0) return 0.0;
        return a / b;
    };
    std::cout << "10 / 3 = " << safeDivide(10, 3) << "\n";
    std::cout << "10 / 0 = " << safeDivide(10, 0) << "\n";

    // 立即呼叫的 lambda(IIFE)
    int result = [](int x, int y) { return x * y; }(6, 7);
    std::cout << "立即呼叫 lambda:6 * 7 = " << result << "\n";

    // ========================================================
    // 2. 捕獲 — 以值捕獲(capture by value)
    // ========================================================
    section("2. 以值捕獲 [=] [x]");

    int base = 100;
    int bonus = 50;

    // [=] 以值捕獲所有外部變數
    auto calcTotal1 = [=]() {
        return base + bonus;
        // base = 200;  // 錯誤!以值捕獲的變數是 const
    };
    std::cout << "[=] base + bonus = " << calcTotal1() << "\n";

    // [base] 只捕獲 base
    auto calcDouble = [base]() {
        return base * 2;
    };
    std::cout << "[base] base * 2 = " << calcDouble() << "\n";

    // 以值捕獲是在 lambda 建立時複製一份
    int x = 10;
    auto snapshot = [x]() { return x; };
    x = 999;  // 修改原始值不影響已捕獲的值
    std::cout << "原始 x = " << x << ",lambda 中 x = " << snapshot() << "\n";

    // ========================================================
    // 3. 捕獲 — 以參考捕獲(capture by reference)
    // ========================================================
    section("3. 以參考捕獲 [&] [&x]");

    int counter = 0;

    // [&] 以參考捕獲所有外部變數
    auto increment = [&]() {
        counter++;  // 直接修改原始變數
    };

    increment();
    increment();
    increment();
    std::cout << "[&] counter = " << counter << "(呼叫 3 次 increment)\n";

    // [&counter] 只以參考捕獲 counter
    auto reset = [&counter]() {
        counter = 0;
    };
    reset();
    std::cout << "reset 後 counter = " << counter << "\n";

    // ========================================================
    // 4. 混合捕獲
    // ========================================================
    section("4. 混合捕獲 [=, &x] [&, x]");

    int total = 0;
    int taxRate = 10;  // 稅率 10%

    // [=, &total]:預設以值捕獲,total 以參考捕獲
    auto addWithTax = [=, &total](int price) {
        int tax = price * taxRate / 100;
        total += price + tax;
        // taxRate = 20;  // 錯誤!taxRate 是以值捕獲的 const
    };

    addWithTax(100);  // 100 + 10 = 110
    addWithTax(200);  // 200 + 20 = 220
    std::cout << "含稅總價:" << total << "\n";

    // [&, taxRate]:預設以參考捕獲,taxRate 以值捕獲
    int count2 = 0;
    auto countExpensive = [&, taxRate](int price) {
        if (price > taxRate * 10) count2++;
        // taxRate = 5;  // 錯誤!taxRate 是以值捕獲的
    };
    countExpensive(50);
    countExpensive(150);
    countExpensive(200);
    std::cout << "超過 100 元的商品有 " << count2 << " 個\n";

    // ========================================================
    // 5. mutable Lambda
    // ========================================================
    section("5. mutable Lambda");

    int seed = 0;

    // mutable 允許修改以值捕獲的變數(修改的是副本)
    auto idGenerator = [seed]() mutable -> int {
        return ++seed;
    };

    std::cout << "生成 ID:";
    for (int i = 0; i < 5; i++) {
        std::cout << idGenerator() << " ";
    }
    std::cout << "\n";
    std::cout << "原始 seed 仍為:" << seed << "(不受影響)\n";

    // ========================================================
    // 6. 泛型 Lambda(auto 參數)
    // ========================================================
    section("6. 泛型 Lambda(C++14)");

    // auto 參數讓 lambda 變成模板
    auto print = [](const auto& x) {
        std::cout << x << "\n";
    };

    std::cout << "印出不同型別:\n";
    print(42);
    print(3.14);
    print("C++ Lambda");
    print(std::string("std::string 型別"));

    // 泛型二元運算
    auto multiply = [](auto a, auto b) {
        return a * b;
    };
    std::cout << "int * int:" << multiply(3, 4) << "\n";
    std::cout << "double * double:" << multiply(2.5, 4.0) << "\n";

    // ========================================================
    // 7. Lambda 搭配 sort
    // ========================================================
    section("7. Lambda + sort");

    struct Student {
        std::string name;
        int score;
    };

    std::vector<Student> students = {
        {"Alice", 88}, {"Bob", 95}, {"Charlie", 72},
        {"Diana", 88}, {"Eve", 91}
    };

    // 按分數降序排列;分數相同按姓名升序
    std::sort(students.begin(), students.end(),
        [](const Student& a, const Student& b) {
            if (a.score != b.score) return a.score > b.score;
            return a.name < b.name;
        });

    std::cout << "排序結果:\n";
    for (const auto& s : students) {
        std::cout << "  " << std::setw(8) << s.name << ":" << s.score << "\n";
    }

    // ========================================================
    // 8. Lambda + find_if / count_if
    // ========================================================
    section("8. Lambda + find_if / count_if");

    std::vector<int> scores = {78, 92, 65, 88, 55, 73, 95, 42, 81, 70};
    printVec("全班成績:", scores);

    // find_if:找第一個不及格的分數
    auto failIt = std::find_if(scores.begin(), scores.end(),
        [](int s) { return s < 60; });
    if (failIt != scores.end()) {
        std::cout << "第一個不及格分數:" << *failIt
                  << "(索引 " << (failIt - scores.begin()) << ")\n";
    }

    // count_if:計算各等級人數
    int gradeA = std::count_if(scores.begin(), scores.end(),
        [](int s) { return s >= 90; });
    int gradeB = std::count_if(scores.begin(), scores.end(),
        [](int s) { return s >= 80 && s < 90; });
    int gradeC = std::count_if(scores.begin(), scores.end(),
        [](int s) { return s >= 70 && s < 80; });
    int gradeD = std::count_if(scores.begin(), scores.end(),
        [](int s) { return s >= 60 && s < 70; });
    int gradeF = std::count_if(scores.begin(), scores.end(),
        [](int s) { return s < 60; });

    std::cout << "A (90-100):" << gradeA << " 人\n";
    std::cout << "B (80-89):" << gradeB << " 人\n";
    std::cout << "C (70-79):" << gradeC << " 人\n";
    std::cout << "D (60-69):" << gradeD << " 人\n";
    std::cout << "F (<60):  " << gradeF << " 人\n";

    // ========================================================
    // 9. Lambda + for_each
    // ========================================================
    section("9. Lambda + for_each");

    std::vector<std::string> fruits = {"蘋果", "香蕉", "櫻桃", "芒果", "葡萄"};

    // 帶索引的 for_each
    int index = 0;
    std::for_each(fruits.begin(), fruits.end(),
        [&index](const std::string& fruit) {
            std::cout << index + 1 << ". " << fruit << "\n";
            index++;
        });

    // ========================================================
    // 10. Lambda + transform
    // ========================================================
    section("10. Lambda + transform");

    std::vector<double> celsius = {0, 20, 37, 100};
    std::vector<double> fahrenheit(celsius.size());

    // 攝氏轉華氏
    std::transform(celsius.begin(), celsius.end(), fahrenheit.begin(),
        [](double c) { return c * 9.0 / 5.0 + 32.0; });

    std::cout << "溫度轉換:\n";
    for (size_t i = 0; i < celsius.size(); i++) {
        std::cout << std::fixed << std::setprecision(1)
                  << "  " << celsius[i] << "°C = "
                  << fahrenheit[i] << "°F\n";
    }

    // ========================================================
    // 11. Lambda 回傳 Lambda(高階函式)
    // ========================================================
    section("11. Lambda 回傳 Lambda");

    // 建立一個乘法器工廠
    auto makeMultiplier = [](int factor) {
        return [factor](int x) { return x * factor; };
    };

    auto double_it = makeMultiplier(2);
    auto triple_it = makeMultiplier(3);

    std::cout << "double_it(5) = " << double_it(5) << "\n";
    std::cout << "triple_it(5) = " << triple_it(5) << "\n";

    // 搭配 transform 使用
    std::vector<int> nums = {1, 2, 3, 4, 5};
    std::vector<int> tripled(nums.size());
    std::transform(nums.begin(), nums.end(), tripled.begin(), triple_it);
    printVec("原始:", nums);
    printVec("三倍:", tripled);

    // ========================================================
    // 12. 綜合範例:資料處理管線
    // ========================================================
    section("12. 綜合範例:資料處理管線");

    struct Product {
        std::string name;
        double price;
        int quantity;
    };

    std::vector<Product> products = {
        {"筆記本", 45.0, 100},
        {"原子筆", 12.0, 500},
        {"橡皮擦", 8.0, 300},
        {"尺", 25.0, 200},
        {"計算機", 350.0, 50},
        {"書包", 890.0, 30}
    };

    // 篩選:價格 > 20
    std::vector<Product> expensive;
    std::copy_if(products.begin(), products.end(),
        std::back_inserter(expensive),
        [](const Product& p) { return p.price > 20.0; });

    // 排序:按價格降序
    std::sort(expensive.begin(), expensive.end(),
        [](const Product& a, const Product& b) {
            return a.price > b.price;
        });

    // 輸出:每個商品的名稱、單價、庫存總價值
    std::cout << "價格 > 20 的商品(按價格降序):\n";
    std::for_each(expensive.begin(), expensive.end(),
        [](const Product& p) {
            double totalValue = p.price * p.quantity;
            std::cout << "  " << std::setw(6) << p.name
                      << "  單價:$" << std::setw(7) << std::fixed
                      << std::setprecision(1) << p.price
                      << "  庫存:" << std::setw(4) << p.quantity
                      << "  總值:$" << std::setw(10) << totalValue << "\n";
        });

    // 計算總庫存價值
    double totalInventory = std::accumulate(products.begin(), products.end(), 0.0,
        [](double acc, const Product& p) {
            return acc + p.price * p.quantity;
        });
    std::cout << "\n所有商品總庫存價值:$"
              << std::fixed << std::setprecision(1) << totalInventory << "\n";

    return 0;
}

Artículos relacionados