C++ SFINAE 双嵌套 initializer_list 与可变参数模板构造函数
C++ SFINAE double nested initializer_list vs. variadic template constructor
问题
我正在编写一个包含 Vector
和 Matrix
class 的小型数学库。我想让这些 classes 的对象使用 严格的初始化规则 来方便地初始化它们。
Vector
class 构造函数已经按照我的预期运行。它受到限制,因此只接受正确的大小 N
并且所有参数都属于同一类型(见下文)。
Vector
template <std::size_t N, typename T>
class Vector{
public:
template <typename... TArgs,
std::enable_if_t<
sizeof...(TArgs) == N &&
(std::is_same_v<T, std::remove_reference_t<TArgs>> && ...),int> = 0>
Vector(TArgs &&... args) : data_{std::forward<TArgs>(args)...} {}
// ...
private:
std::array<T,N> data;
}
示例初始化(有效,受限)
Vector<3,int> v{1,2,3}
Matrix
template <std::size_t N, std::size_t M, typename T>
class Matrix{
public:
/* put restriction rules here */
Matrix(std::initializer_list<std::initializer_list<T>> lst) {
int i = 0;
int j = 0;
for (const auto &l : lst) {
for (const auto &v : l) {
data[i][j] = v;
++j;
}
j = 0;
++i;
}
}
// ...
private:
std::array<Vector<M, T>, N> data;
}
实例初始化1(有效,不受限制)
Matrix<2,3,int> m{ {1,2,3}, {4,5,6} }
示例初始化 2(编译,但不应该!!)
Matrix<2,3,int> m{ {1,'a',3}, {4,5,6,7,8,9} }
问题
我无法使用可变模板为双嵌套初始化实现 Matrix
class 构造函数,所以我使用了嵌套 std::initializer_list
(来自 this post)。它有效,但我想对此构造函数有与 Vector
class.
相同的限制
我该怎么做?
- 列表大小必须为 N(行)
- 列表列表大小必须始终为 M(列)
- 封装的值类型必须始终为 T
附加信息
这里 post 关于这个... ::std::initializer_list vs variadic templates 我可以说我真的不喜欢使用 initializer_list 或可变参数模板。在这种情况下,任何一个似乎都不错,但据我所知,在编译时获得 std::initializer_list
的大小有些困难。
您可以简单地使 Matrix
像这样获取二维数组引用:
Matrix(T const (&m)[N][M])
这只会在您指定的条件下进行编译,调整其余代码也很容易。您可以应用相同的原理来简化 Vector
.
要获得所需的语法,您可以这样做:
template <typename ... Us,
std::enable_if_t<sizeof...(Us) == N && (std::is_same_v<Us, T> && ...), int> = 0>
Matrix(const Us (&... rows)[M]) {
// ...
}
问题
我正在编写一个包含 Vector
和 Matrix
class 的小型数学库。我想让这些 classes 的对象使用 严格的初始化规则 来方便地初始化它们。
Vector
class 构造函数已经按照我的预期运行。它受到限制,因此只接受正确的大小 N
并且所有参数都属于同一类型(见下文)。
Vector
template <std::size_t N, typename T>
class Vector{
public:
template <typename... TArgs,
std::enable_if_t<
sizeof...(TArgs) == N &&
(std::is_same_v<T, std::remove_reference_t<TArgs>> && ...),int> = 0>
Vector(TArgs &&... args) : data_{std::forward<TArgs>(args)...} {}
// ...
private:
std::array<T,N> data;
}
示例初始化(有效,受限)
Vector<3,int> v{1,2,3}
Matrix
template <std::size_t N, std::size_t M, typename T>
class Matrix{
public:
/* put restriction rules here */
Matrix(std::initializer_list<std::initializer_list<T>> lst) {
int i = 0;
int j = 0;
for (const auto &l : lst) {
for (const auto &v : l) {
data[i][j] = v;
++j;
}
j = 0;
++i;
}
}
// ...
private:
std::array<Vector<M, T>, N> data;
}
实例初始化1(有效,不受限制)
Matrix<2,3,int> m{ {1,2,3}, {4,5,6} }
示例初始化 2(编译,但不应该!!)
Matrix<2,3,int> m{ {1,'a',3}, {4,5,6,7,8,9} }
问题
我无法使用可变模板为双嵌套初始化实现 Matrix
class 构造函数,所以我使用了嵌套 std::initializer_list
(来自 this post)。它有效,但我想对此构造函数有与 Vector
class.
我该怎么做?
- 列表大小必须为 N(行)
- 列表列表大小必须始终为 M(列)
- 封装的值类型必须始终为 T
附加信息
这里 post 关于这个... ::std::initializer_list vs variadic templates 我可以说我真的不喜欢使用 initializer_list 或可变参数模板。在这种情况下,任何一个似乎都不错,但据我所知,在编译时获得 std::initializer_list
的大小有些困难。
您可以简单地使 Matrix
像这样获取二维数组引用:
Matrix(T const (&m)[N][M])
这只会在您指定的条件下进行编译,调整其余代码也很容易。您可以应用相同的原理来简化 Vector
.
要获得所需的语法,您可以这样做:
template <typename ... Us,
std::enable_if_t<sizeof...(Us) == N && (std::is_same_v<Us, T> && ...), int> = 0>
Matrix(const Us (&... rows)[M]) {
// ...
}