测试_第21章_元编程.cpp

← 测试总览 · 目录

编译运行: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;
}