二维数组的自动尺寸扣除
Automatic size deduction for two-dimensional array
我正在尝试制作一个固定大小的矩阵 class。目的是让它继承或利用 std::array
of std::array
:
template <size_t Rows, size_t Columns, class T=double>
struct Matrix : public std::array<std::array<T, Columns>, Rows> {
};
我想提供一个可以自动推断大小的初始化器,就像 std::array
在 C++17 中(我正在使用的)一样。我也可以使用函数来制作 Matrix
而不是使用 class 模板参数推导。
// What I want, but does not work:
Matrix matrix {{1., 2.},
{3., 4.}};
// Or:
auto matrix = MakeMatrix ({1., 2.},
{3., 4.});
我没能实现其中任何一个。相反,只有以下工作:
// Requires specifying the size and repeating `std::array`, both undesired
Matrix<2,2> mat {
std::array{1., 2.},
std::array{3., 4.}
};
// OR this, which requires specifying the size and is generally confusing
Matrix<2,2> mat2 {1., 2.,
3., 4.};
我尝试使用可变参数模板,但这对编译器也没有吸引力:
template<class... Args>
auto MakeMatrix (Args... args) {
return Matrix{ std::array {args} ... };
}
// This causes compiler error:
// error: no matching function for call to 'MakeMatrix'
// candidate function [with Args = <>] not viable: requires 0 arguments, but 2 were provided
auto matrix = MakeMatrix ({1., 2.},
{3., 4.});
// This causes compiler error
// error: no viable constructor or deduction guide for deduction of template arguments of 'Matrix'
// note: in instantiation of function template specialization 'MakeMatrix<std::__1::array<double, 2>, std::__1::array<double, 2> >'
// note: note: candidate function template not viable: requires 0 arguments, but 2 were provided
auto matrix = MakeMatrix (std::array {1., 2.},
std::array {3., 4.});
我也考虑过使用 std::initializer_list<std::initializer_list<T>>
,但是据我所知这些不支持固定大小,我希望在编译时确定大小。
关于如何做到这一点的任何想法,或者对于当前的 C++ 机制来说这根本不可能吗?
问题是编译器在用作参数时无法推导出 {}
。这适用于 initializer_list
(对于构造函数,由于一些特殊规则)。但是你错过了尺寸。
解决方法是内置数组:
template <typename T, size_t N>
using Row = const T (&)[N]; // for readability
template <auto Rows, auto Columns, typename T = double>
class Matrix {
public:
template <typename... Ts, auto N>
Matrix(Row<Ts, N>... rows) {}
};
template <typename... RowTypes, auto Columns>
Matrix(Row<RowTypes, Columns>...)
-> Matrix<sizeof...(RowTypes), Columns, std::common_type_t<RowTypes...>>;
您现在可以完全按照自己的喜好构建 Matrix
:
const auto m = Matrix{{1, 2}, {1, 2}, {1, 2}};
对于最后一步,使用内置数组初始化 std::array
可能很棘手。 C++20 提供了一个 function,检查 link 以了解可能的实现。如果您复制该实现,或者有一个可用的实现,您可以轻松创建构造函数,如:
template <auto Rows, auto Columns, typename T = double>
class Matrix {
public:
template <typename... Ts, auto N>
Matrix(Row<Ts, N>... rows) {
data_ = {to_array(rows)...};
}
private:
std::array<std::array<T, Columns>, Rows> data_;
};
Live example, with operator[]
to show that the data layout is correct.
我正在尝试制作一个固定大小的矩阵 class。目的是让它继承或利用 std::array
of std::array
:
template <size_t Rows, size_t Columns, class T=double>
struct Matrix : public std::array<std::array<T, Columns>, Rows> {
};
我想提供一个可以自动推断大小的初始化器,就像 std::array
在 C++17 中(我正在使用的)一样。我也可以使用函数来制作 Matrix
而不是使用 class 模板参数推导。
// What I want, but does not work:
Matrix matrix {{1., 2.},
{3., 4.}};
// Or:
auto matrix = MakeMatrix ({1., 2.},
{3., 4.});
我没能实现其中任何一个。相反,只有以下工作:
// Requires specifying the size and repeating `std::array`, both undesired
Matrix<2,2> mat {
std::array{1., 2.},
std::array{3., 4.}
};
// OR this, which requires specifying the size and is generally confusing
Matrix<2,2> mat2 {1., 2.,
3., 4.};
我尝试使用可变参数模板,但这对编译器也没有吸引力:
template<class... Args>
auto MakeMatrix (Args... args) {
return Matrix{ std::array {args} ... };
}
// This causes compiler error:
// error: no matching function for call to 'MakeMatrix'
// candidate function [with Args = <>] not viable: requires 0 arguments, but 2 were provided
auto matrix = MakeMatrix ({1., 2.},
{3., 4.});
// This causes compiler error
// error: no viable constructor or deduction guide for deduction of template arguments of 'Matrix'
// note: in instantiation of function template specialization 'MakeMatrix<std::__1::array<double, 2>, std::__1::array<double, 2> >'
// note: note: candidate function template not viable: requires 0 arguments, but 2 were provided
auto matrix = MakeMatrix (std::array {1., 2.},
std::array {3., 4.});
我也考虑过使用 std::initializer_list<std::initializer_list<T>>
,但是据我所知这些不支持固定大小,我希望在编译时确定大小。
关于如何做到这一点的任何想法,或者对于当前的 C++ 机制来说这根本不可能吗?
问题是编译器在用作参数时无法推导出 {}
。这适用于 initializer_list
(对于构造函数,由于一些特殊规则)。但是你错过了尺寸。
解决方法是内置数组:
template <typename T, size_t N>
using Row = const T (&)[N]; // for readability
template <auto Rows, auto Columns, typename T = double>
class Matrix {
public:
template <typename... Ts, auto N>
Matrix(Row<Ts, N>... rows) {}
};
template <typename... RowTypes, auto Columns>
Matrix(Row<RowTypes, Columns>...)
-> Matrix<sizeof...(RowTypes), Columns, std::common_type_t<RowTypes...>>;
您现在可以完全按照自己的喜好构建 Matrix
:
const auto m = Matrix{{1, 2}, {1, 2}, {1, 2}};
对于最后一步,使用内置数组初始化 std::array
可能很棘手。 C++20 提供了一个 function,检查 link 以了解可能的实现。如果您复制该实现,或者有一个可用的实现,您可以轻松创建构造函数,如:
template <auto Rows, auto Columns, typename T = double>
class Matrix {
public:
template <typename... Ts, auto N>
Matrix(Row<Ts, N>... rows) {
data_ = {to_array(rows)...};
}
private:
std::array<std::array<T, Columns>, Rows> data_;
};
Live example, with operator[]
to show that the data layout is correct.