用另一个 constexpr 数组对成员数组进行大括号初始化

Brace initialization of a member array with another constexpr array

本文关键字:数组 初始化 成员 另一个 constexpr      更新时间:2023-10-16

让我们考虑以下说明性示例代码:

using matrix_t = double[2][2];
constexpr matrix_t zero_matrix = {
    {0.0, 0.0},
    {0.0, 0.0}
};
constexpr matrix_t identity_matrix = {
    {1.0, 0.0},
    {0.0, 1.0}
};
struct wrapped_matrix_t
{
    matrix_t matrix;
};
constexpr wrapped_matrix_t zero_wrapped_matrix = {
    //zero_matrix
    {
        {zero_matrix[0][0], zero_matrix[0][1]},
        {zero_matrix[1][0], zero_matrix[1][1]}
    }
};
constexpr wrapped_matrix_t identity_wrapped_matrix = {
    //identity_matrix
    {
        {identity_matrix[0][0], identity_matrix[0][1]},
        {identity_matrix[1][0], identity_matrix[1][1]}
    }
};

现在我希望能够通过constexpr数组zero_matrixidentity_matrix来初始化其他类型的matrix_t成员。然而,这似乎是不可能的。或者至少简单地使用名称是行不通的。

我得出的最好的结果是重用值来引用索引。但这远非完美。

有没有办法在这样的初始化中直接使用 zero_matrixidentity_matrix

(我正在用-Wall -Wextra -pedantic -std=c++11检查GCC 6.3.0。

如果您不能使用 std::array 并且无法访问 wrapped_matrix_t 的实现,则可以在初始化包装器时使用元编程生成源数组的索引。最终代码将如下所示:

constexpr wrapped_matrix_t zero_wrapped_matrix = from_array(zero_matrix);
constexpr wrapped_matrix_t identity_wrapped_matrix = from_array(identity_matrix);

我假设matrix_tdouble[2 * 2],但下面的技术可以推广到N维数组。

以下是实现详细信息:

template <typename Array, std::size_t... Is>
constexpr auto from_array_impl(const Array& arr, std::index_sequence<Is...>)
{
    return wrapped_matrix_t{arr[Is]...};
}
template <std::size_t N>
constexpr auto from_array(const double(&arr)[N])
{
    return from_array_impl(arr, std::make_index_sequence<N>());
}

我基本上是将数组的大小与引用相匹配,并从中构建一个0..N索引序列。然后,我通过用序列索引数组来创建wrapped_matrix_t

魔杖盒上的现场示例


以下是 2D 数组的可能实现:

template <std::size_t W, typename Array, std::size_t... Is>
constexpr auto from_array_impl(const Array& arr, std::index_sequence<Is...>)
{
    return wrapped_matrix_t{(arr[Is % W][Is / W])...};
}
template <std::size_t W, std::size_t H>
constexpr auto from_array(const double(&arr)[W][H])
{
    return from_array_impl<W>(arr, std::make_index_sequence<W * H>());
}

魔杖盒上的现场示例

您可以使用

std::array并将表示形式更改为一维数组。

using matrix_t = std::array<double, 2 * 2>;
constexpr matrix_t zero_matrix = {
    {0.0, 0.0,
     0.0, 0.0}
};
constexpr matrix_t identity_matrix = {
    {1.0, 0.0,
     0.0, 1.0}
};
struct wrapped_matrix_t
{
    matrix_t matrix;
};
constexpr wrapped_matrix_t zero_wrapped_matrix{zero_matrix};
constexpr wrapped_matrix_t identity_wrapped_matrix{zero_matrix};

魔杖盒上的现场示例


为了像访问 2D 数组一样访问 1D 数组,您可以使用以下公式: (x, y) => x + y * width .

如果您愿意,可以在std::array周围创建一个包装器,以提供类似 2D 的界面。