c++ - 使用 Lamba 函数初始化 constexpr
问题描述
语境
我正在编写一个用于培训的数学库。现在我正在研究 Matrix 类。我正在尝试创建一个identityMatrix()
函数。这是一个模板化的函数,它构建并返回一个单位矩阵。现在我的代码是:
template<index_t N, typename Scalar = double>
constexpr inline static const Matrix<N, N, Scalar> identityMatrix() noexcept
{
constexpr static Matrix<N, N, Scalar> id = []
{
Matrix<N, N, Scalar> m(0);
for (index_t i = 0; i < N; i++)
{
m.at(i, i) = static_cast<Scalar>(1.0);
}
return m;
}();
return id;
}
我正在尝试使其仅在需要时才构建一次矩阵,以后对该函数的任何引用都会返回一个函数本地静态常量对象。由于初始化很复杂,我正在使用 lambda 并立即调用它。Matrix
定义如下:
using index_t = uint32_t;
#define FOR(i, N) for(index_t i = 0; i < N; ++i)
#define FORiN(N) FOR(i, N)
template<index_t ROWS, index_t COLS = ROWS, typename Scalar = double>
struct Matrix
{
static constexpr auto BUFFER_SIZE = ROWS * COLS;
Scalar buffer[BUFFER_SIZE];
//...
constexpr Matrix() noexcept = default;
constexpr Matrix(const Scalar (&init_data)[BUFFER_SIZE]) noexcept
{
memcpy_s(buffer, BUFFER_SIZE * sizeof Scalar, &init_data , BUFFER_SIZE * sizeof Scalar);
}
constexpr Matrix(const std::initializer_list<std::initializer_list<Scalar>>& init_data)
{
static_assert(init_data.size() == ROWS && init_data.begin()->size() == COLS);
FOR(row_index, ROWS)
{
Scalar* src_row = &init_data.begin()[row_index];
Scalar* dst_row = &buffer[row_index * COLS];
constexpr index_t row_size_bytes = COLS * sizeof Scalar;
memcpy_s(dst_row, row_size_bytes, src_row, row_size_bytes);
}
}
constexpr Matrix(Scalar homogenuos_value) noexcept
{
std::fill_n(buffer, BUFFER_SIZE, homogenuos_value);
}
constexpr Matrix(const Matrix& rhs) noexcept
{
FOR(i, BUFFER_SIZE)
buffer[i] = rhs.buffer[i];
}
inline constexpr static index_t indexOf(index_t col, index_t row) { return row * COLS + col; }
inline constexpr Scalar& at(index_t row, index_t col) { return buffer[indexOf(row, col)]; }
inline constexpr const Scalar& at(index_t row, index_t col) const { return buffer[indexOf(row, col)]; }
//... more operators and stuff
};
问题
我为测试矩阵代码而编写的测试代码如下:
constexpr auto id = identityMatrix<3>();
constexpr auto manual_id = Matrix<3, 3>({ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 });
static_assert(id == manual_id);
print(id);
为什么
为什么这不起作用?我已经使所有 constexpr
这在编译时都应该保持不变。编译器应该能够做到这一点。我错过了什么?我究竟做错了什么?
环境
我在用着
Microsoft Visual Studio Professional 2019 - 版本 16.4.2
平台工具集:Visual Studio 2019 (v142)
C++ 语言标准:预览 - 最新 C++ 工作草案中的功能 (std:c++latest)
今天日期:2020 年 6 月 9 日
解决方案
这是因为该函数memcpy_s
不是 constexpr 函数。
当编译器解析模板化的 constexpr 函数时,它不会检查这些函数是否为 constexpr。相反,它在这些函数的实例化时检查 constexprness。如果这些实例不是 constexpr,则这不是错误。
这就是这里发生的事情,没有一个Matrix<3,3>
构造函数是 constexpr 因为memcpy_s
不是 constexpr。
推荐阅读
- asp.net - Payu的支付api验证不起作用
- node.js - 有没有办法在 node.js 中自动添加一对对象的每个元素?
- arrays - c中每个数字的第k个数字
- python - 在 Python 中将字符串转换为多维数组
- javascript - React clearInterval 不会停止计时器
- wear-os - 如何在华为 GT 2 Pro 中编写应用程序以始终保持在屏幕上处于活动状态?
- laravel - 如何在不知道其列 laravel 的情况下定义 casts 属性
- apache-spark - Spark JVM RSS 内存(执行程序物理内存使用)
- javascript - 如何将对象键与数组值进行比较并为变量赋值?
- kubernetes - 如何使用 kubectl 修补 statefulset envFrom