시리즈: C++
cpp
585 줄
· 업데이트 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;
}
관련 글
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).
글 읽기 →