### C++中constexpr实现编译期矩阵乘法的完整示例

在C++20及以后,constexpr已足够强大,可在编译期完成复杂运算。本文演示如何使用constexpr实现一个二维矩阵乘法,并通过编译期验证其正确性。代码兼容C++17(需开启constexpr容器),在C++20更简洁。

1. 设计矩阵类型

#include <array>
#include <iostream>
#include <utility>

template <std::size_t N, std::size_t M>
struct Matrix {
    std::array<std::array<int, M>, N> data{};

    constexpr int& operator()(std::size_t i, std::size_t j) {
        return data[i][j];
    }
    constexpr const int& operator()(std::size_t i, std::size_t j) const {
        return data[i][j];
    }
};
  • Matrix 用二维 std::array 存储数据,编译期可完整初始化。
  • 提供了访问符 (),方便读写。

2. 乘法实现

template <std::size_t N, std::size_t K, std::size_t M>
constexpr Matrix<N, M> mul(const Matrix<N, K>& A, const Matrix<K, M>& B) {
    Matrix<N, M> C{};
    for (std::size_t i = 0; i < N; ++i)
        for (std::size_t j = 0; j < M; ++j) {
            int sum = 0;
            for (std::size_t k = 0; k < K; ++k)
                sum += A(i, k) * B(k, j);
            C(i, j) = sum;
        }
    return C;
}
  • 采用三层循环完成矩阵乘法。
  • 所有变量均为 constexpr,循环使用 std::size_t,保证可在编译期展开。

3. 编译期验证

constexpr Matrix<2, 3> A{ { {1, 2, 3}, {4, 5, 6} } };
constexpr Matrix<3, 2> B{ { {7, 8}, {9, 10}, {11, 12} } };

constexpr auto C = mul(A, B);   // 计算在编译期完成

static_assert(C(0, 0) == 1*7 + 2*9 + 3*11, "编译期验证失败");
static_assert(C(1, 1) == 4*8 + 5*10 + 6*12, "编译期验证失败");
  • static_assert 用于在编译期检查结果,若不匹配则编译错误。

4. 运行时输出

int main() {
    for (std::size_t i = 0; i < 2; ++i) {
        for (std::size_t j = 0; j < 2; ++j) {
            std::cout << C(i, j) << ' ';
        }
        std::cout << '\n';
    }
}

运行后得到:

58 64 
139 154 

这正是矩阵 A 与 B 的乘积。

5. 进一步优化

  • 递归模板:在 C++14/17 中,可使用递归模板实现更通用的矩阵乘法。
  • 并行计算:利用 std::execution::parstd::transform_reduce 在运行时并行化。
  • 通用数值类型:将 int 替换为 auto 或模板参数 T,支持浮点数、复数等。

6. 小结

  • constexprstd::array 搭配,可以在编译期完成矩阵运算。
  • 通过 static_assert 实时验证结果,提升代码安全性。
  • 这种技术适用于需要大量预计算或生成固定参数表的场景,例如游戏图形、密码学等。

希望这篇文章能帮助你更好地利用 C++ 的编译期特性,实现高效、可靠的矩阵运算。

发表评论