用另一个 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_matrix
和 identity_matrix
来初始化其他类型的 matrix_t
成员。然而,这似乎是不可能的。或者至少简单地使用名称是行不通的。
我得出的最好结果是重用引用索引的值。但这远非完美。
有没有办法直接在这样的初始化中使用zero_matrix
和identity_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};
为了像访问二维数组一样访问一维数组,您可以使用以下公式:(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_t
是 double[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
。
这是二维数组的可能实现:
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>());
}
让我们考虑以下示例代码:
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_matrix
和 identity_matrix
来初始化其他类型的 matrix_t
成员。然而,这似乎是不可能的。或者至少简单地使用名称是行不通的。
我得出的最好结果是重用引用索引的值。但这远非完美。
有没有办法直接在这样的初始化中使用zero_matrix
和identity_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};
为了像访问二维数组一样访问一维数组,您可以使用以下公式:(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_t
是 double[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
。
这是二维数组的可能实现:
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>());
}