编译运行:clang++ -std=c++26 -Wall -Wextra -pthread 测试_第21章_元编程.cpp -o t && ./t(需先 cd 测试/)
// 第21章测试:元编程与编译期计算
#include <print>
#include <array>
#include <tuple>
#include <type_traits>
#include <concepts>
#include <cmath>
#include <string>
#include <string_view>
int failures = 0;
#define CHECK(expr) \
do { \
if (!(expr)) { \
++failures; \
std::println("FAIL 第{}行: {}", __LINE__, #expr); \
} \
} while (0)
// 21.2 编译期阶乘(constexpr 循环,C++14 起)
constexpr int factorial(int n) {
int r = 1;
for (int i = 2; i <= n; ++i) r *= i;
return r;
}
static_assert(factorial(5) == 120);
// 练习1:编译期整数幂
constexpr int cpow(int base, int exp) {
int r = 1;
for (int i = 0; i < exp; ++i) r *= base;
return r;
}
static_assert(cpow(2, 10) == 1024);
// 21.4 if constexpr 分派(返回 string_view,避免指针比较陷阱)
template <typename T>
std::string_view describe(const T&) {
if constexpr (std::integral<T>) return "整数";
else if constexpr (std::same_as<T, double>) return "double";
else if constexpr (std::same_as<std::decay_t<T>, std::string>) return "string";
else return "其他";
}
// 练习2:编译期素数数组(埃氏筛 constexpr 版)
constexpr auto sieve_constexpr(int limit) {
std::array<int, 25> primes{}; // 100 以内 25 个素数
int count = 0;
bool comp[101] = {};
for (int i = 2; i <= limit; ++i) {
if (!comp[i]) {
primes[count++] = i;
for (int j = i * i; j <= limit; j += i) comp[j] = true;
}
}
return primes;
}
constexpr auto PRIMES = sieve_constexpr(100);
static_assert(PRIMES[0] == 2);
static_assert(PRIMES[24] == 97);
static_assert(PRIMES[10] == 31);
// 21.5 TypeList
template <typename... Ts>
struct TypeList {
static constexpr std::size_t size = sizeof...(Ts);
template <std::size_t I>
using at = std::tuple_element_t<I, std::tuple<Ts...>>;
};
using L = TypeList<int, double, char>;
static_assert(L::size == 3);
static_assert(std::is_same_v<L::at<1>, double>);
// 21.5 折叠求和
template <typename... Ts>
auto fold_sum(Ts... args) { return (args + ...); }
// 21.8 编译期查表(std::sin 在本机 libc++ 中还不是 constexpr,
// 因此用泰勒级数前 5 项近似——也展示了 constexpr 函数的写法)
constexpr double pi = 3.14159265358979;
constexpr double csin(double x) { // 泰勒展开近似
double term = x, sum = x;
for (int i = 1; i <= 5; ++i) {
term = -term * x * x / (2.0 * i * (2.0 * i + 1));
sum += term;
}
return sum;
}
static_assert(csin(pi / 2) > 0.999 && csin(pi / 2) < 1.001);
constexpr auto make_sin_table() {
std::array<double, 64> table{};
for (int i = 0; i < 64; ++i)
table[i] = csin(pi * i / 64.0);
return table;
}
constexpr auto SIN_TABLE = make_sin_table();
// 21.6 concepts 取代 SFINAE
template <std::integral T>
void only_int(T) {}
int main() {
// 21.2/练习1:编译期结果直接可用
CHECK(factorial(6) == 720);
CHECK(cpow(3, 4) == 81);
// 21.4 分派
CHECK(describe(42) == "整数");
CHECK(describe(3.14) == "double");
CHECK(describe(std::string("x")) == "string");
CHECK(describe('a') == "整数"); // char 也是 integral
// 21.5
CHECK(fold_sum(1, 2, 3, 4, 5) == 15);
CHECK(fold_sum(1.5, 2.5) == 4.0);
CHECK(fold_sum(std::string("a"), std::string("b")) == "ab");
// 21.8 查表验证(与 csin 直接计算对比)
CHECK(std::abs(SIN_TABLE[16] - csin(pi / 4)) < 1e-15);
CHECK(SIN_TABLE[0] == 0.0);
CHECK(std::abs(SIN_TABLE[32] - 1.0) < 1e-3); // sin(pi/2)≈1
// 21.6 concepts
only_int(5);
// only_int(5.0); // 编译错误:double 不满足 integral
// 编译期 vs 运行期验证
CHECK(PRIMES[24] == 97);
if (failures == 0) std::println("全部通过");
return failures;
}