使用lamba函数初始化constexpr

问题描述 投票:0回答:1

上下文

我正在写一个用于培训的数学库。现在,我正在研究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;
}

我正在尝试使它仅在需要时才构建一次矩阵,以后对该函数的任何引用都会返回一个函数局部静态const对象。由于初始化很复杂,因此我使用了lambda并立即对其进行了调用。Matrix定义如下:

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);

Visual Studio给我这个:并且:

为什么

为什么这不起作用?我做了everything constexpr,这在编译时应该是恒定的。编译器应该能够做到这一点。我想念什么?我在做什么错?

环境

我正在使用

Microsoft Visual Studio Professional 2019-版本16.4.2 平台工具集:Visual Studio 2019(v142) C ++语言标准:预览-最新C ++工作草案中的功能(std:c ++ latest) 今天的日期:2020年6月9日

c++ matrix initialization constexpr compile-time
1个回答
1
投票

这是因为函数memcpy_s不是constexpr函数。

当编译器解析模板化的constexpr函数时,它不会检查那些函数是否为constexpr。而是在这些函数的实例化时检查constexprness。如果这些实例不是constexpr,则不是错误。

这就是这里发生的情况,Matrix<3,3>构造函数都不是constexpr,因为memcpy_s不是constexpr。

© www.soinside.com 2019 - 2024. All rights reserved.