Series: C++
cpp
362 lines
· Updated 2026-04-03
constexpr_basics.cpp
C++/Part5_進階主題/Ch22_constexpr與編譯期計算/constexpr_basics.cpp
// constexpr_basics.cpp
// 編譯指令:g++ -std=c++17 -Wall constexpr_basics.cpp -o constexpr_basics
//
// 本程式示範 constexpr 的基本用法:變數、函式、static_assert
#include <iostream>
#include <array>
#include <cmath>
#include <string_view>
// ============================================================
// 第一部分:constexpr 變數
// ============================================================
constexpr int MAX_BUFFER_SIZE = 1024;
constexpr double PI = 3.14159265358979323846;
constexpr double TAU = 2.0 * PI;
constexpr int GRID_SIZE = 8;
constexpr int TOTAL_CELLS = GRID_SIZE * GRID_SIZE; // constexpr 可以引用其他 constexpr
void demo_constexpr_variables() {
std::cout << "========================================\n";
std::cout << " constexpr 變數\n";
std::cout << "========================================\n\n";
// constexpr 值可以用作陣列大小
int buffer[MAX_BUFFER_SIZE];
int grid[GRID_SIZE][GRID_SIZE];
(void)buffer; (void)grid;
std::cout << "MAX_BUFFER_SIZE = " << MAX_BUFFER_SIZE << "\n";
std::cout << "PI = " << PI << "\n";
std::cout << "TAU = " << TAU << "\n";
std::cout << "GRID_SIZE = " << GRID_SIZE << "\n";
std::cout << "TOTAL_CELLS = " << TOTAL_CELLS << "\n";
// 對比:const 不一定是編譯期
const int runtime_const = std::cin.peek(); // 執行期才知道
// constexpr int x = runtime_const; // 錯誤!無法在編譯期確定
(void)runtime_const;
std::cout << "\nconst 可以在執行期初始化,constexpr 不行\n";
std::cout << "\n";
}
// ============================================================
// 第二部分:constexpr 函式 — 基本範例
// ============================================================
constexpr int factorial(int n) {
int result = 1;
for (int i = 2; i <= n; ++i) {
result *= i;
}
return result;
}
constexpr long long fibonacci(int n) {
if (n <= 1) return n;
long long a = 0, b = 1;
for (int i = 2; i <= n; ++i) {
long long temp = a + b;
a = b;
b = temp;
}
return b;
}
constexpr bool is_prime(int n) {
if (n < 2) return false;
if (n == 2) return true;
if (n % 2 == 0) return false;
for (int i = 3; i * i <= n; i += 2) {
if (n % i == 0) return false;
}
return true;
}
constexpr int gcd(int a, int b) {
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
void demo_constexpr_functions() {
std::cout << "========================================\n";
std::cout << " constexpr 函式\n";
std::cout << "========================================\n\n";
// 編譯期求值
constexpr int fact5 = factorial(5);
constexpr long long fib10 = fibonacci(10);
constexpr bool prime17 = is_prime(17);
constexpr int gcd_12_8 = gcd(12, 8);
std::cout << "factorial(5) = " << fact5 << "\n";
std::cout << "fibonacci(10) = " << fib10 << "\n";
std::cout << "is_prime(17) = " << std::boolalpha << prime17 << "\n";
std::cout << "gcd(12, 8) = " << gcd_12_8 << "\n";
// constexpr 函式也可以在執行期使用
int n;
std::cout << "\n(在執行期使用 constexpr 函式)\n";
n = 7;
std::cout << "factorial(" << n << ") = " << factorial(n) << "\n";
std::cout << "fibonacci(" << n << ") = " << fibonacci(n) << "\n";
std::cout << "is_prime(" << n << ") = " << std::boolalpha << is_prime(n) << "\n";
// 印出質數列表
std::cout << "\n2 到 50 之間的質數:\n ";
for (int i = 2; i <= 50; ++i) {
if (is_prime(i)) std::cout << i << " ";
}
std::cout << "\n\n";
}
// ============================================================
// 第三部分:static_assert 與 constexpr
// ============================================================
constexpr int PROTOCOL_VERSION = 3;
constexpr int MIN_VERSION = 2;
constexpr int MAX_VERSION = 5;
// 編譯期驗證配置
static_assert(PROTOCOL_VERSION >= MIN_VERSION, "協議版本過低");
static_assert(PROTOCOL_VERSION <= MAX_VERSION, "協議版本過高");
static_assert(MAX_BUFFER_SIZE >= 256, "緩衝區必須至少 256 bytes");
static_assert(MAX_BUFFER_SIZE % 8 == 0, "緩衝區大小必須是 8 的倍數");
// 驗證自定義函式的結果
static_assert(factorial(5) == 120, "factorial 計算錯誤");
static_assert(fibonacci(10) == 55, "fibonacci 計算錯誤");
static_assert(is_prime(7), "7 應該是質數");
static_assert(!is_prime(4), "4 不應該是質數");
static_assert(gcd(12, 8) == 4, "gcd 計算錯誤");
void demo_static_assert() {
std::cout << "========================================\n";
std::cout << " static_assert 編譯期驗證\n";
std::cout << "========================================\n\n";
std::cout << "以下 static_assert 在編譯期已通過驗證:\n";
std::cout << " ✓ PROTOCOL_VERSION 在 [" << MIN_VERSION << ", " << MAX_VERSION << "] 範圍內\n";
std::cout << " ✓ MAX_BUFFER_SIZE (" << MAX_BUFFER_SIZE << ") >= 256\n";
std::cout << " ✓ MAX_BUFFER_SIZE 是 8 的倍數\n";
std::cout << " ✓ factorial(5) == 120\n";
std::cout << " ✓ fibonacci(10) == 55\n";
std::cout << " ✓ is_prime(7) == true\n";
std::cout << " ✓ gcd(12, 8) == 4\n";
std::cout << "\n如果任何斷言失敗,程式無法編譯\n";
// 型別特性的 static_assert
static_assert(sizeof(int) >= 4, "int 至少需要 4 bytes");
static_assert(sizeof(long long) >= 8, "long long 至少需要 8 bytes");
std::cout << " ✓ sizeof(int) = " << sizeof(int) << " >= 4\n";
std::cout << " ✓ sizeof(long long) = " << sizeof(long long) << " >= 8\n";
std::cout << "\n";
}
// ============================================================
// 第四部分:const vs constexpr 比較
// ============================================================
// constexpr 保證在編譯期確定
int get_runtime_value() {
return 42;
}
void demo_const_vs_constexpr() {
std::cout << "========================================\n";
std::cout << " const vs constexpr 比較\n";
std::cout << "========================================\n\n";
const int a = 10; // 編譯期已知(但不強制)
const int b = get_runtime_value(); // 執行期才知道
constexpr int c = 10; // 編譯期保證
// constexpr int d = get_runtime_value(); // 編譯錯誤!
// const 可用於某些編譯期情境(如果編譯器能推導)
// 但 constexpr 更明確
int arr1[a]; // 可能 OK(編譯器特定行為)
int arr2[c]; // 一定 OK
(void)arr1; (void)arr2;
std::cout << "const int a = 10; // 可以是編譯期\n";
std::cout << "const int b = get_runtime(); // 只能是執行期\n";
std::cout << "constexpr int c = 10; // 保證編譯期\n";
std::cout << "// constexpr int d = get_runtime(); // 編譯錯誤\n\n";
// constexpr 隱含 const
// constexpr int x = 10;
// x = 20; // 錯誤:constexpr 變數隱含 const
std::cout << "constexpr 變數隱含 const,不可修改\n";
// const 指標 vs constexpr 指標
static constexpr int value = 100;
constexpr const int* ptr = &value; // 指標本身是 constexpr,指向 const int
std::cout << "constexpr const int* ptr = &value; // *ptr = " << *ptr << "\n";
(void)b; (void)ptr;
std::cout << "\n";
}
// ============================================================
// 第五部分:constexpr 與陣列
// ============================================================
// 編譯期產生乘法表
constexpr auto make_multiplication_table() {
std::array<std::array<int, 10>, 10> table{};
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
table[i][j] = (i + 1) * (j + 1);
}
}
return table;
}
// 編譯期產生平方表
constexpr auto make_square_table() {
std::array<int, 20> table{};
for (int i = 0; i < 20; ++i) {
table[i] = i * i;
}
return table;
}
// 編譯期字串長度計算
constexpr std::size_t string_length(const char* str) {
std::size_t len = 0;
while (str[len] != '\0') ++len;
return len;
}
// 編譯期字元統計
constexpr int count_char(std::string_view sv, char c) {
int count = 0;
for (char ch : sv) {
if (ch == c) ++count;
}
return count;
}
constexpr auto mult_table = make_multiplication_table();
constexpr auto square_table = make_square_table();
void demo_constexpr_arrays() {
std::cout << "========================================\n";
std::cout << " constexpr 與陣列\n";
std::cout << "========================================\n\n";
// 印出部分乘法表
std::cout << "編譯期乘法表(部分):\n";
std::cout << " ";
for (int j = 0; j < 10; ++j) std::cout << (j + 1) << "\t";
std::cout << "\n " << std::string(80, '-') << "\n";
for (int i = 0; i < 5; ++i) {
std::cout << (i + 1) << " | ";
for (int j = 0; j < 10; ++j) {
std::cout << mult_table[i][j] << "\t";
}
std::cout << "\n";
}
std::cout << " ... (後面省略)\n";
// 平方表
std::cout << "\n編譯期平方表:\n ";
for (int i = 0; i < 20; ++i) {
std::cout << i << "²=" << square_table[i];
if (i < 19) std::cout << ", ";
if (i == 9) std::cout << "\n ";
}
std::cout << "\n";
// 編譯期字串操作
constexpr auto len = string_length("Hello, World!");
constexpr auto vowels = count_char("Hello World", 'l');
static_assert(len == 13, "字串長度計算錯誤");
std::cout << "\n編譯期字串操作:\n";
std::cout << " \"Hello, World!\" 長度 = " << len << "\n";
std::cout << " \"Hello World\" 中 'l' 出現 " << vowels << " 次\n";
std::cout << "\n";
}
// ============================================================
// 第六部分:constexpr 階乘與費波那契表
// ============================================================
constexpr auto make_factorial_table() {
std::array<long long, 21> table{};
table[0] = 1;
for (int i = 1; i <= 20; ++i) {
table[i] = table[i - 1] * i;
}
return table;
}
constexpr auto make_fibonacci_table() {
std::array<long long, 50> table{};
table[0] = 0;
table[1] = 1;
for (int i = 2; i < 50; ++i) {
table[i] = table[i - 1] + table[i - 2];
}
return table;
}
constexpr auto factorials = make_factorial_table();
constexpr auto fibonaccis = make_fibonacci_table();
static_assert(factorials[0] == 1);
static_assert(factorials[5] == 120);
static_assert(factorials[10] == 3628800);
static_assert(fibonaccis[10] == 55);
void demo_precomputed_tables() {
std::cout << "========================================\n";
std::cout << " 編譯期預計算表\n";
std::cout << "========================================\n\n";
std::cout << "階乘表(0! ~ 20!):\n";
for (int i = 0; i <= 20; ++i) {
std::cout << " " << i << "! = " << factorials[i] << "\n";
}
std::cout << "\n費波那契數列(前 20 個):\n ";
for (int i = 0; i < 20; ++i) {
std::cout << fibonaccis[i];
if (i < 19) std::cout << ", ";
if (i == 9) std::cout << "\n ";
}
std::cout << "\n\n";
std::cout << "這些表格在編譯期就已經計算完成,\n";
std::cout << "執行期查詢只需要 O(1) 時間。\n";
std::cout << "\n";
}
// ============================================================
// 主程式
// ============================================================
int main() {
std::cout << "╔══════════════════════════════════════╗\n";
std::cout << "║ C++17 constexpr 基礎 ║\n";
std::cout << "╚══════════════════════════════════════╝\n\n";
demo_constexpr_variables();
demo_constexpr_functions();
demo_static_assert();
demo_const_vs_constexpr();
demo_constexpr_arrays();
demo_precomputed_tables();
std::cout << "=== 程式結束 ===\n";
return 0;
}
Related articles
C++
c
Updated 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/deviceAlpha.h).
Read article →
C++
c
Updated 2026-07-21
finalproject.c
finalproject.c — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.c).
Read article →
C++
cpp
Updated 2026-07-21
finalproject.cpp
finalproject.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.cpp).
Read article →
C++
c
Updated 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/deviceAlpha.h).
Read article →
C++
c
Updated 2026-07-21
lab8.c
lab8.c — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.c).
Read article →
C++
cpp
Updated 2026-07-21
lab8.cpp
lab8.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.cpp).
Read article →