如何扩展多个 index_sequence 参数包以在 C++ 中初始化二维数组?
How to expand multiple index_sequence parameter packs to initialize 2d array in C++?
我正在尝试用 std::initializer_list
初始化我的 Matrix
class。我知道我可以用 std::index_sequence
做到这一点,但我不知道如何在一个语句中扩展它们。
我是这样做的:
template<size_t rows, size_t cols>
class Matrix {
public:
Matrix(std::initializer_list<std::initializer_list<float>> il)
: Matrix(il,
std::make_index_sequence<rows>(),
std::make_index_sequence<cols>()) {}
private:
template<size_t... RowIs, size_t... ColIs>
Matrix(std::initializer_list<std::initializer_list<float>> il,
std::index_sequence<RowIs...>,
std::index_sequence<ColIs...>)
: values_{
{
il.begin()[RowIs].begin()[ColIs]...
}...
} {}
public:
float values_[rows][cols] = {};
};
第二次扩展失败,错误 Pack expansion does not contain any unexpanded parameter packs
。也许我可以以某种方式指定要扩展的参数包?
希望得到您的帮助!
如果您可以访问 C++20,则可以让构造函数采用 (const
) 引用 rows
x [= 的二维 C-style 数组13=] 元素。然后你可以只扩展行,让 std::to_array
为你做剩下的:
#include <array>
#include <cstdint>
template <std::size_t rows, std::size_t cols>
class Matrix {
public:
Matrix(float const (&il)[rows][cols])
: Matrix(il, std::make_index_sequence<rows>()) {}
private:
template <std::size_t... RowIs>
Matrix(float const (&il)[rows][cols], std::index_sequence<RowIs...>)
: values_{std::to_array(il[RowIs])...} {}
public:
std::array<std::array<float, cols>, rows> values_;
};
int main() {
Matrix<2, 3> m({{1, 2, 3}, {4, 5, 6}});
}
如果您无权访问 std::to_array
,您自己实现它非常容易(在命名空间 std
之外)。
我认为问题出在 RowIs
和 ColIs
同时扩展的事实,即两者在初始化期间始终具有相同的值:0、1、2.. .
您可以检查 here 您当前的输出(修复编译器错误后)是否类似于
[[1.1, 5.5, 9.9], [0, 0, 0], [0, 0, 0]]
对于下面的矩阵:
Matrix<3, 3> m{
{ 1.1, 2.2, 3.3 },
{ 4.4, 5.5, 6.6 },
{ 7.7, 8.8, 9.9 }
};
因为您只读取了il[0,0]
、il[1,1]
和il[2,2]
以便设置values_
。
你可以做的是创建一个具有平面索引的序列,从 0
到 Rows*Cols - 1
,并使用 FlatIs/Rows
和 [从 il
读取每个值=23=]:
#include <array>
#include <cstdint>
#include <fmt/ranges.h>
#include <initializer_list>
#include <utility>
template<std::size_t Rows, std::size_t Cols>
class Matrix {
public:
Matrix(std::initializer_list<std::initializer_list<float>> il)
: Matrix(il, std::make_index_sequence<Rows*Cols>())
{}
private:
template<std::size_t... FlatIs>
Matrix(std::initializer_list<std::initializer_list<float>> il,
std::index_sequence<FlatIs...>)
: values_{il.begin()[FlatIs/Rows].begin()[FlatIs%Cols]...}
{}
public:
std::array<std::array<float, Cols>, Rows> values_;
};
int main() {
Matrix<3, 3> m{
{ 1.1, 2.2, 3.3 },
{ 4.4, 5.5, 6.6 },
{ 7.7, 8.8, 9.9 }
};
fmt::print("{}", m.values_);
}
// Outputs:
//
// [[1.1, 2.2, 3.3], [4.4, 5.5, 6.6], [7.7, 8.8, 9.9]]
我正在尝试用 std::initializer_list
初始化我的 Matrix
class。我知道我可以用 std::index_sequence
做到这一点,但我不知道如何在一个语句中扩展它们。
我是这样做的:
template<size_t rows, size_t cols>
class Matrix {
public:
Matrix(std::initializer_list<std::initializer_list<float>> il)
: Matrix(il,
std::make_index_sequence<rows>(),
std::make_index_sequence<cols>()) {}
private:
template<size_t... RowIs, size_t... ColIs>
Matrix(std::initializer_list<std::initializer_list<float>> il,
std::index_sequence<RowIs...>,
std::index_sequence<ColIs...>)
: values_{
{
il.begin()[RowIs].begin()[ColIs]...
}...
} {}
public:
float values_[rows][cols] = {};
};
第二次扩展失败,错误 Pack expansion does not contain any unexpanded parameter packs
。也许我可以以某种方式指定要扩展的参数包?
希望得到您的帮助!
如果您可以访问 C++20,则可以让构造函数采用 (const
) 引用 rows
x [= 的二维 C-style 数组13=] 元素。然后你可以只扩展行,让 std::to_array
为你做剩下的:
#include <array>
#include <cstdint>
template <std::size_t rows, std::size_t cols>
class Matrix {
public:
Matrix(float const (&il)[rows][cols])
: Matrix(il, std::make_index_sequence<rows>()) {}
private:
template <std::size_t... RowIs>
Matrix(float const (&il)[rows][cols], std::index_sequence<RowIs...>)
: values_{std::to_array(il[RowIs])...} {}
public:
std::array<std::array<float, cols>, rows> values_;
};
int main() {
Matrix<2, 3> m({{1, 2, 3}, {4, 5, 6}});
}
如果您无权访问 std::to_array
,您自己实现它非常容易(在命名空间 std
之外)。
我认为问题出在 RowIs
和 ColIs
同时扩展的事实,即两者在初始化期间始终具有相同的值:0、1、2.. .
您可以检查 here 您当前的输出(修复编译器错误后)是否类似于
[[1.1, 5.5, 9.9], [0, 0, 0], [0, 0, 0]]
对于下面的矩阵:
Matrix<3, 3> m{
{ 1.1, 2.2, 3.3 },
{ 4.4, 5.5, 6.6 },
{ 7.7, 8.8, 9.9 }
};
因为您只读取了il[0,0]
、il[1,1]
和il[2,2]
以便设置values_
。
你可以做的是创建一个具有平面索引的序列,从 0
到 Rows*Cols - 1
,并使用 FlatIs/Rows
和 [从 il
读取每个值=23=]:
#include <array>
#include <cstdint>
#include <fmt/ranges.h>
#include <initializer_list>
#include <utility>
template<std::size_t Rows, std::size_t Cols>
class Matrix {
public:
Matrix(std::initializer_list<std::initializer_list<float>> il)
: Matrix(il, std::make_index_sequence<Rows*Cols>())
{}
private:
template<std::size_t... FlatIs>
Matrix(std::initializer_list<std::initializer_list<float>> il,
std::index_sequence<FlatIs...>)
: values_{il.begin()[FlatIs/Rows].begin()[FlatIs%Cols]...}
{}
public:
std::array<std::array<float, Cols>, Rows> values_;
};
int main() {
Matrix<3, 3> m{
{ 1.1, 2.2, 3.3 },
{ 4.4, 5.5, 6.6 },
{ 7.7, 8.8, 9.9 }
};
fmt::print("{}", m.values_);
}
// Outputs:
//
// [[1.1, 2.2, 3.3], [4.4, 5.5, 6.6], [7.7, 8.8, 9.9]]