S SmartDocs
Chuỗi bài: C++ cpp 585 dòng · Cập nhật 2026-04-03

constexpr_advanced.cpp

C++/Part5_進階主題/Ch22_constexpr與編譯期計算/constexpr_advanced.cpp

// constexpr_advanced.cpp
// 編譯指令:g++ -std=c++17 -Wall constexpr_advanced.cpp -o constexpr_advanced
//
// 本程式示範 constexpr 的進階應用:constexpr 類別、if constexpr、
// 編譯期字串處理、constexpr lambda、編譯期查找表

#include <iostream>
#include <array>
#include <string>
#include <string_view>
#include <type_traits>
#include <cstdint>
#include <cmath>

// ============================================================
// 第一部分:constexpr 類別 — Point
// ============================================================

class Point {
    double x_, y_;

public:
    constexpr Point(double x = 0.0, double y = 0.0) : x_(x), y_(y) {}

    constexpr double x() const { return x_; }
    constexpr double y() const { return y_; }

    constexpr Point operator+(const Point& other) const {
        return {x_ + other.x_, y_ + other.y_};
    }

    constexpr Point operator-(const Point& other) const {
        return {x_ - other.x_, y_ - other.y_};
    }

    constexpr Point operator*(double scalar) const {
        return {x_ * scalar, y_ * scalar};
    }

    constexpr double dot(const Point& other) const {
        return x_ * other.x_ + y_ * other.y_;
    }

    constexpr double distance_squared(const Point& other) const {
        double dx = x_ - other.x_;
        double dy = y_ - other.y_;
        return dx * dx + dy * dy;
    }

    constexpr Point midpoint(const Point& other) const {
        return {(x_ + other.x_) / 2.0, (y_ + other.y_) / 2.0};
    }

    constexpr bool operator==(const Point& other) const {
        return x_ == other.x_ && y_ == other.y_;
    }
};

constexpr Point operator*(double scalar, const Point& p) {
    return p * scalar;
}

void demo_constexpr_point() {
    std::cout << "========================================\n";
    std::cout << "  constexpr 類別:Point\n";
    std::cout << "========================================\n\n";

    constexpr Point origin;
    constexpr Point a(3.0, 4.0);
    constexpr Point b(6.0, 8.0);

    constexpr Point sum = a + b;
    constexpr Point mid = a.midpoint(b);
    constexpr double dist_sq = a.distance_squared(origin);
    constexpr double dot_product = a.dot(b);
    constexpr Point scaled = a * 2.0;

    // 編譯期驗證
    static_assert(origin.x() == 0.0 && origin.y() == 0.0);
    static_assert(sum.x() == 9.0 && sum.y() == 12.0);
    static_assert(dist_sq == 25.0);  // 3² + 4² = 25

    std::cout << "origin     = (" << origin.x() << ", " << origin.y() << ")\n";
    std::cout << "a          = (" << a.x() << ", " << a.y() << ")\n";
    std::cout << "b          = (" << b.x() << ", " << b.y() << ")\n";
    std::cout << "a + b      = (" << sum.x() << ", " << sum.y() << ")\n";
    std::cout << "midpoint   = (" << mid.x() << ", " << mid.y() << ")\n";
    std::cout << "dist²(a,0) = " << dist_sq << "\n";
    std::cout << "a · b      = " << dot_product << "\n";
    std::cout << "a * 2      = (" << scaled.x() << ", " << scaled.y() << ")\n";
    std::cout << "\n以上所有計算在編譯期完成!\n\n";
}

// ============================================================
// 第二部分:constexpr 類別 — Color
// ============================================================

class Color {
    uint8_t r_, g_, b_, a_;

public:
    constexpr Color(uint8_t r = 0, uint8_t g = 0, uint8_t b = 0, uint8_t a = 255)
        : r_(r), g_(g), b_(b), a_(a) {}

    constexpr uint8_t r() const { return r_; }
    constexpr uint8_t g() const { return g_; }
    constexpr uint8_t b() const { return b_; }
    constexpr uint8_t a() const { return a_; }

    // 編譯期顏色混合(線性插值)
    constexpr Color blend(const Color& other, double t) const {
        auto lerp = [](uint8_t a, uint8_t b, double t) -> uint8_t {
            return static_cast<uint8_t>(a + (b - a) * t);
        };
        return {lerp(r_, other.r_, t), lerp(g_, other.g_, t),
                lerp(b_, other.b_, t), lerp(a_, other.a_, t)};
    }

    // 轉為 32 位整數 (RGBA)
    constexpr uint32_t to_rgba() const {
        return (static_cast<uint32_t>(r_) << 24) |
               (static_cast<uint32_t>(g_) << 16) |
               (static_cast<uint32_t>(b_) << 8)  |
               static_cast<uint32_t>(a_);
    }

    // 從 32 位整數建構
    static constexpr Color from_rgba(uint32_t rgba) {
        return {static_cast<uint8_t>((rgba >> 24) & 0xFF),
                static_cast<uint8_t>((rgba >> 16) & 0xFF),
                static_cast<uint8_t>((rgba >> 8) & 0xFF),
                static_cast<uint8_t>(rgba & 0xFF)};
    }

    // 亮度(灰階值)
    constexpr uint8_t luminance() const {
        return static_cast<uint8_t>(0.299 * r_ + 0.587 * g_ + 0.114 * b_);
    }
};

// 預定義顏色常數
constexpr Color RED(255, 0, 0);
constexpr Color GREEN(0, 255, 0);
constexpr Color BLUE(0, 0, 255);
[[maybe_unused]] constexpr Color WHITE(255, 255, 255);
[[maybe_unused]] constexpr Color BLACK(0, 0, 0);

void demo_constexpr_color() {
    std::cout << "========================================\n";
    std::cout << "  constexpr 類別:Color\n";
    std::cout << "========================================\n\n";

    constexpr Color orange = RED.blend(Color(255, 255, 0), 0.5);
    constexpr Color purple = RED.blend(BLUE, 0.5);
    constexpr auto red_rgba = RED.to_rgba();
    constexpr auto reconstructed = Color::from_rgba(red_rgba);
    constexpr auto red_lum = RED.luminance();

    static_assert(reconstructed.r() == 255 && reconstructed.g() == 0 && reconstructed.b() == 0);

    auto print_color = [](const std::string& name, const Color& c) {
        std::cout << name << " = RGBA("
                  << static_cast<int>(c.r()) << ", "
                  << static_cast<int>(c.g()) << ", "
                  << static_cast<int>(c.b()) << ", "
                  << static_cast<int>(c.a()) << ")"
                  << " 亮度=" << static_cast<int>(c.luminance()) << "\n";
    };

    print_color("RED    ", RED);
    print_color("GREEN  ", GREEN);
    print_color("BLUE   ", BLUE);
    print_color("orange ", orange);
    print_color("purple ", purple);

    std::cout << "\nRED 的 RGBA 整數 = 0x" << std::hex << red_rgba << std::dec << "\n";
    std::cout << "RED 的亮度 = " << static_cast<int>(red_lum) << "\n";
    std::cout << "\n";
}

// ============================================================
// 第三部分:if constexpr — 型別分派
// ============================================================

// 根據型別在編譯期選擇不同的處理邏輯
template<typename T>
auto type_describe() -> std::string {
    if constexpr (std::is_integral_v<T>) {
        if constexpr (std::is_signed_v<T>)
            return "有號整數";
        else
            return "無號整數";
    } else if constexpr (std::is_floating_point_v<T>) {
        return "浮點數";
    } else if constexpr (std::is_same_v<T, std::string>) {
        return "字串";
    } else if constexpr (std::is_pointer_v<T>) {
        return "指標";
    } else {
        return "未知型別";
    }
}

// 根據型別選擇不同的預設值
template<typename T>
constexpr T default_value() {
    if constexpr (std::is_integral_v<T>) {
        return T{0};
    } else if constexpr (std::is_floating_point_v<T>) {
        return T{0.0};
    } else if constexpr (std::is_pointer_v<T>) {
        return nullptr;
    } else {
        return T{};
    }
}

// 安全轉換:只在有意義的型別間轉換
template<typename To, typename From>
auto safe_convert(From value) -> To {
    if constexpr (std::is_same_v<To, From>) {
        return value;
    } else if constexpr (std::is_arithmetic_v<To> && std::is_arithmetic_v<From>) {
        return static_cast<To>(value);
    } else if constexpr (std::is_same_v<To, std::string> && std::is_arithmetic_v<From>) {
        return std::to_string(value);
    } else {
        static_assert(std::is_convertible_v<From, To>, "無法轉換的型別組合");
        return static_cast<To>(value);
    }
}

void demo_if_constexpr() {
    std::cout << "========================================\n";
    std::cout << "  if constexpr 型別分派\n";
    std::cout << "========================================\n\n";

    std::cout << "型別描述:\n";
    std::cout << "  int           -> " << type_describe<int>() << "\n";
    std::cout << "  unsigned long -> " << type_describe<unsigned long>() << "\n";
    std::cout << "  double        -> " << type_describe<double>() << "\n";
    std::cout << "  std::string   -> " << type_describe<std::string>() << "\n";
    std::cout << "  int*          -> " << type_describe<int*>() << "\n";

    std::cout << "\n預設值(由 if constexpr 決定):\n";
    std::cout << "  int    -> " << default_value<int>() << "\n";
    std::cout << "  double -> " << default_value<double>() << "\n";
    std::cout << "  bool   -> " << std::boolalpha << default_value<bool>() << "\n";

    std::cout << "\n安全轉換:\n";
    auto s1 = safe_convert<std::string>(42);
    auto s2 = safe_convert<std::string>(3.14);
    auto d1 = safe_convert<double>(42);
    std::cout << "  int -> string:    \"" << s1 << "\"\n";
    std::cout << "  double -> string: \"" << s2 << "\"\n";
    std::cout << "  int -> double:    " << d1 << "\n";
    std::cout << "\n";
}

// ============================================================
// 第四部分:if constexpr — 遞迴模板展開
// ============================================================

// 編譯期計算可變參數的總和
template<typename T>
constexpr T sum(T value) {
    return value;
}

template<typename T, typename... Args>
constexpr auto sum(T first, Args... rest) {
    return first + sum(rest...);
}

// 使用 if constexpr 的版本(更簡潔)
template<typename T, typename... Args>
constexpr auto sum_v2(T first, Args... rest) {
    if constexpr (sizeof...(rest) == 0) {
        return first;
    } else {
        return first + sum_v2(rest...);
    }
}

// 編譯期計算所有參數中的最大值
template<typename T>
constexpr T max_of(T value) {
    return value;
}

template<typename T, typename... Args>
constexpr T max_of(T first, Args... rest) {
    if constexpr (sizeof...(rest) == 0) {
        return first;
    } else {
        T rest_max = max_of(rest...);
        return first > rest_max ? first : rest_max;
    }
}

// 印出所有參數(非 constexpr,但使用 if constexpr 控制遞迴)
template<typename T, typename... Args>
void print_all(const T& first, const Args&... rest) {
    std::cout << first;
    if constexpr (sizeof...(rest) > 0) {
        std::cout << ", ";
        print_all(rest...);
    }
}

void demo_variadic_constexpr() {
    std::cout << "========================================\n";
    std::cout << "  if constexpr 與可變參數模板\n";
    std::cout << "========================================\n\n";

    constexpr auto s1 = sum_v2(1, 2, 3, 4, 5);
    constexpr auto s2 = sum_v2(1.1, 2.2, 3.3);
    constexpr auto m1 = max_of(3, 7, 2, 9, 4);

    static_assert(s1 == 15);
    static_assert(m1 == 9);

    std::cout << "sum_v2(1,2,3,4,5) = " << s1 << "\n";
    std::cout << "sum_v2(1.1,2.2,3.3) = " << s2 << "\n";
    std::cout << "max_of(3,7,2,9,4) = " << m1 << "\n";

    std::cout << "\nprint_all 輸出: ";
    print_all(42, " hello ", 3.14, " world ", true);
    std::cout << "\n\n";
}

// ============================================================
// 第五部分:編譯期字串處理
// ============================================================

// constexpr 字串比較
constexpr bool str_equal(std::string_view a, std::string_view b) {
    if (a.size() != b.size()) return false;
    for (std::size_t i = 0; i < a.size(); ++i) {
        if (a[i] != b[i]) return false;
    }
    return true;
}

// constexpr 子字串搜尋
constexpr int str_find(std::string_view haystack, std::string_view needle) {
    if (needle.empty()) return 0;
    if (needle.size() > haystack.size()) return -1;
    for (std::size_t i = 0; i <= haystack.size() - needle.size(); ++i) {
        bool match = true;
        for (std::size_t j = 0; j < needle.size(); ++j) {
            if (haystack[i + j] != needle[j]) {
                match = false;
                break;
            }
        }
        if (match) return static_cast<int>(i);
    }
    return -1;
}

// constexpr 大小寫轉換(ASCII)
constexpr char to_upper(char c) {
    return (c >= 'a' && c <= 'z') ? static_cast<char>(c - 32) : c;
}

constexpr char to_lower(char c) {
    return (c >= 'A' && c <= 'Z') ? static_cast<char>(c + 32) : c;
}

// constexpr 雜湊(簡化版 FNV-1a)
constexpr uint32_t fnv1a_hash(std::string_view sv) {
    uint32_t hash = 2166136261u;
    for (char c : sv) {
        hash ^= static_cast<uint32_t>(c);
        hash *= 16777619u;
    }
    return hash;
}

void demo_constexpr_strings() {
    std::cout << "========================================\n";
    std::cout << "  編譯期字串處理\n";
    std::cout << "========================================\n\n";

    constexpr bool eq = str_equal("hello", "hello");
    constexpr bool neq = str_equal("hello", "world");
    constexpr int pos = str_find("Hello, World!", "World");
    constexpr int not_found = str_find("Hello", "xyz");

    static_assert(eq == true);
    static_assert(neq == false);
    static_assert(pos == 7);
    static_assert(not_found == -1);

    std::cout << "str_equal(\"hello\", \"hello\") = " << std::boolalpha << eq << "\n";
    std::cout << "str_equal(\"hello\", \"world\") = " << neq << "\n";
    std::cout << "str_find(\"Hello, World!\", \"World\") = " << pos << "\n";
    std::cout << "str_find(\"Hello\", \"xyz\") = " << not_found << "\n";

    // 編譯期雜湊
    constexpr auto hash1 = fnv1a_hash("hello");
    constexpr auto hash2 = fnv1a_hash("Hello");
    constexpr auto hash3 = fnv1a_hash("hello");

    static_assert(hash1 == hash3);
    static_assert(hash1 != hash2);

    std::cout << "\nFNV-1a 雜湊:\n";
    std::cout << "  hash(\"hello\") = 0x" << std::hex << hash1 << "\n";
    std::cout << "  hash(\"Hello\") = 0x" << hash2 << "\n";
    std::cout << "  hash1 == hash3: " << std::dec << std::boolalpha << (hash1 == hash3) << "\n";
    std::cout << "\n";
}

// ============================================================
// 第六部分:constexpr lambda(C++17)
// ============================================================

void demo_constexpr_lambda() {
    std::cout << "========================================\n";
    std::cout << "  constexpr lambda(C++17)\n";
    std::cout << "========================================\n\n";

    // C++17 起,lambda 預設就是 constexpr(如果可能的話)
    constexpr auto square = [](int x) { return x * x; };
    constexpr auto cube = [](int x) { return x * x * x; };

    constexpr int sq5 = square(5);
    constexpr int cu3 = cube(3);

    static_assert(sq5 == 25);
    static_assert(cu3 == 27);

    std::cout << "square(5) = " << sq5 << "\n";
    std::cout << "cube(3)   = " << cu3 << "\n";

    // constexpr lambda 與陣列
    constexpr auto make_powers = [](int base) {
        std::array<int, 10> result{};
        int power = 1;
        for (int i = 0; i < 10; ++i) {
            result[i] = power;
            power *= base;
        }
        return result;
    };

    constexpr auto powers_of_2 = make_powers(2);
    constexpr auto powers_of_3 = make_powers(3);

    static_assert(powers_of_2[0] == 1);
    static_assert(powers_of_2[10 - 1] == 512);

    std::cout << "\n2 的次方(編譯期計算):\n  ";
    for (int i = 0; i < 10; ++i) {
        std::cout << "2^" << i << "=" << powers_of_2[i];
        if (i < 9) std::cout << ", ";
    }

    std::cout << "\n3 的次方(編譯期計算):\n  ";
    for (int i = 0; i < 10; ++i) {
        std::cout << "3^" << i << "=" << powers_of_3[i];
        if (i < 9) std::cout << ", ";
    }
    std::cout << "\n\n";
}

// ============================================================
// 第七部分:編譯期查找表生成
// ============================================================

// CRC32 查找表(編譯期生成)
constexpr auto make_crc32_table() {
    std::array<uint32_t, 256> table{};
    for (uint32_t i = 0; i < 256; ++i) {
        uint32_t crc = i;
        for (int j = 0; j < 8; ++j) {
            if (crc & 1)
                crc = (crc >> 1) ^ 0xEDB88320;
            else
                crc >>= 1;
        }
        table[i] = crc;
    }
    return table;
}

constexpr auto crc32_table = make_crc32_table();

// 使用查找表計算 CRC32
constexpr uint32_t crc32(std::string_view data) {
    uint32_t crc = 0xFFFFFFFF;
    for (char c : data) {
        uint8_t index = static_cast<uint8_t>(crc ^ static_cast<uint8_t>(c));
        crc = (crc >> 8) ^ crc32_table[index];
    }
    return crc ^ 0xFFFFFFFF;
}

// ASCII 字元分類查找表
constexpr auto make_char_class_table() {
    struct CharClass {
        bool is_digit;
        bool is_upper;
        bool is_lower;
        bool is_alpha;
        bool is_alnum;
        bool is_space;
    };

    std::array<CharClass, 128> table{};
    for (int i = 0; i < 128; ++i) {
        char c = static_cast<char>(i);
        table[i].is_digit = (c >= '0' && c <= '9');
        table[i].is_upper = (c >= 'A' && c <= 'Z');
        table[i].is_lower = (c >= 'a' && c <= 'z');
        table[i].is_alpha = table[i].is_upper || table[i].is_lower;
        table[i].is_alnum = table[i].is_alpha || table[i].is_digit;
        table[i].is_space = (c == ' ' || c == '\t' || c == '\n' ||
                             c == '\r' || c == '\f' || c == '\v');
    }
    return table;
}

constexpr auto char_class = make_char_class_table();

static_assert(char_class['A'].is_upper);
static_assert(char_class['a'].is_lower);
static_assert(char_class['5'].is_digit);
static_assert(char_class[' '].is_space);

void demo_lookup_tables() {
    std::cout << "========================================\n";
    std::cout << "  編譯期查找表\n";
    std::cout << "========================================\n\n";

    // CRC32
    constexpr auto crc_hello = crc32("Hello, World!");
    constexpr auto crc_test = crc32("test");

    std::cout << "CRC32 查找表(前 8 個值):\n  ";
    for (int i = 0; i < 8; ++i) {
        std::cout << "0x" << std::hex << crc32_table[i] << " ";
    }
    std::cout << std::dec << "\n\n";

    std::cout << "CRC32 計算結果:\n";
    std::cout << "  crc32(\"Hello, World!\") = 0x" << std::hex << crc_hello << "\n";
    std::cout << "  crc32(\"test\")          = 0x" << crc_test << std::dec << "\n";

    // 字元分類
    std::cout << "\n字元分類查找表測試:\n";
    std::string test_chars = "A a 5 ! \t";
    for (char c : test_chars) {
        if (static_cast<unsigned char>(c) >= 128) continue;
        const auto& cc = char_class[static_cast<unsigned char>(c)];
        std::cout << "  '" << (c == '\t' ? "\\t" : std::string(1, c))
                  << "': digit=" << cc.is_digit
                  << " alpha=" << cc.is_alpha
                  << " space=" << cc.is_space << "\n";
    }
    std::cout << "\n所有查找表在編譯期生成,執行期查詢時間為 O(1)\n\n";
}

// ============================================================
// 主程式
// ============================================================

int main() {
    std::cout << "╔══════════════════════════════════════╗\n";
    std::cout << "║  C++17 constexpr 進階應用              ║\n";
    std::cout << "╚══════════════════════════════════════╝\n\n";

    demo_constexpr_point();
    demo_constexpr_color();
    demo_if_constexpr();
    demo_variadic_constexpr();
    demo_constexpr_strings();
    demo_constexpr_lambda();
    demo_lookup_tables();

    std::cout << "=== 程式結束 ===\n";
    return 0;
}

Bài viết liên quan