用另一个 constexpr 数组支撑成员数组的初始化

Brace initialization of a member array with another constexpr array

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

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 并将您的表示更改为一维数组。

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

live example on wandbox


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

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

如果您不能使用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

live example on wandbox


这是二维数组的可能实现:

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

live example on wandbox