在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::par与std::transform_reduce在运行时并行化。 - 通用数值类型:将
int替换为auto或模板参数T,支持浮点数、复数等。
6. 小结
constexpr与std::array搭配,可以在编译期完成矩阵运算。- 通过
static_assert实时验证结果,提升代码安全性。 - 这种技术适用于需要大量预计算或生成固定参数表的场景,例如游戏图形、密码学等。
希望这篇文章能帮助你更好地利用 C++ 的编译期特性,实现高效、可靠的矩阵运算。