如何在c++中扩展多个index_sequence参数包来初始化2d数组?



我试图用std::initializer_lists初始化我的Matrix类。我知道我可以用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。也许我可以指定我想要展开的参数包?希望您的帮助!

我认为问题来自RowIsColIs同时扩展的事实,即在初始化期间始终具有相同的值:0,1,2…

您可以在这里检查您的当前输出(修复编译器错误后)将是类似的[[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 }
};

因为为了设置values_,您只读取il[0,0],il[1,1]il[2,2]


您可以做的是创建一个具有平面索引的序列,从0Rows*Cols - 1,并用FlatIs/ColsFlatIs%Cols读取il中的每个值:

(演示)

#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/Cols].begin()[FlatIs%Cols]...}
{}
public:
std::array<std::array<float, Cols>, Rows> values_;
};
int main() {
Matrix<4, 3> m{
{ 1.1, 2.2, 3.3 },
{ 4.4, 5.5, 6.6 },
{ 7.7, 8.8, 9.9 },
{ 3.1, 4.1, 5.9 }
};
fmt::print("{}", m.values_);
}
// Outputs:
//
//   [[1.1, 2.2, 3.3], [4.4, 5.5, 6.6], [7.7, 8.8, 9.9], [3.1, 4.1, 5.9]]

如果您可以访问c++ 20,则可以让构造函数接受(const)对rowsxcols元素的二维C风格数组的引用。然后,您可以只展开行,让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之外)。

相关内容

  • 没有找到相关文章

最新更新