在 2d C 数组上使用 std::transform 到 1d C 数组
using std::transform on a 2d C array into a 1d C array
我正在尝试使用 std::transform
将(Foo
结构的简单二维数组转换为 Bar
结构的一维(转换)数组。
// convert 2d array of Foo structs to 1d array of Bar structs
// suitable for constructing a Baz struct.
Foo array2d[3][2] =
{
{
{1,2}, {3,4}
},
{
{5,6}, {7,8}
},
{
{9,10}, {11,12}
}
};
这个简单示例中的转换只是颠倒字段顺序,因为两个结构实际上是同一类型。在我的应用程序中,这些是完全不同的类型。
using Foo = struct {
uint32_t a;
uint32_t b;
};
using Bar = struct {
uint32_t c;
uint32_t d;
};
想法是,这个 Bar 结构的一维数组可用于构造 Baz
结构。
我在使用 lambda 转换器时遇到问题。我相信外部的一次占用一行,而内部的一次占用一列,而实际的 Foo->Bar 转换发生。在现场演示中,我不得不注释掉 std::transform 采用二维数组并将其替换为扁平化版本,我将二维数组转换为一维数组(大小为行乘以列)。这工作完美 - 但我试图坚持参数类型而不必求助于 reinterpret_cast<>.
std::vector<Bar> array1d;
array1d.reserve(Baz::gArraySize);
#if 0
// I don't know how to use the transform on the 2d array
std::transform(std::cbegin(array2d), std::cend(array2d),
std::back_inserter(array1d),
[](const Foo(&rRow)[Baz::gNumCols]) {
std::transform(std::cbegin(rRow), std::cend(rRow),
[](const Foo& rNext) -> Bar {
// reverse the order of the fields
return Bar{ rNext.b, rNext.a };
});
});
#else
// Only workaround is to cast the 2d array to a 1d array using reinterpret cast<>
const auto& special = reinterpret_cast<const Foo(&)[Baz::gArraySize]>(array2d);
// I don't know how to use the transform on the 2d array
std::transform(std::cbegin(special), std::cend(special),
std::back_inserter(array1d),
[](const Foo& rNext) -> Bar {
// reverse the order of the fields
return Bar{ rNext.b, rNext.a };
});
#endif
// construct from transformed 2d array
Baz myBaz(reinterpret_cast<const Bar(&)[Baz::gArraySize]>(array1d[0]));
std::cout << myBaz;
生成如下预期输出:
g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
Bar{c=2, d=1},
Bar{c=4, d=3},
Bar{c=6, d=5},
Bar{c=8, d=7},
Bar{c=10, d=9},
Bar{c=12, d=11},
由于这些结构来自外部源,因此结构采用类似于 C 的数组形式。我不确定 std::transform 我想做的事情是否可行,但我想使用 STL 算法而不是手动解开循环。
我创建了以下 live coliru demo 来展示我试图实现的目标 - 但它在适当的转换中出现了很多错误。请注意,传递给 Baz 的数组取决于 std::vector 在内存中连续分配数据结构这一事实(这是由 STL 保证的)。
struct Baz {
constexpr static int gNumRows = 3;
constexpr static int gNumCols = 2;
constexpr static int gArraySize = gNumRows * gNumCols;
Bar arrayField[gArraySize];
// explicit constructor from C style fixed size array.
explicit Baz(const Bar(&rParam)[gArraySize])
: arrayField{}
{
std::memcpy(arrayField, rParam, gArraySize * sizeof(Bar));
}
friend std::ostream& operator<<(
std::ostream& os, const Baz& rhs) {
for (auto next : rhs.arrayField) {
os << "Bar{c=" << next.c << ", d=" << next.d << "},\n";
}
return os;
}
};
你传递给外部 transform
的 lambda 没有 return 任何东西而且它真的不能因为它应该 return one 输入范围(您的二维数组)的每个元素的值。但是该数组的每个元素都有 两个 值,因此 transform
的每次迭代都会产生两个值,而它应该产生一个值,这就是为什么你不能使用 transform
这里
鉴于此,在此处使用简单循环会更容易且可读性更高:
for (auto &&row : array2d)
for (auto &&foo : row)
oneDimArray.push_back(Bar{ foo.b, foo.a });
将 STL 算法留给实际让您的生活更轻松的情况:)。
我正在尝试使用 std::transform
将(Foo
结构的简单二维数组转换为 Bar
结构的一维(转换)数组。
// convert 2d array of Foo structs to 1d array of Bar structs
// suitable for constructing a Baz struct.
Foo array2d[3][2] =
{
{
{1,2}, {3,4}
},
{
{5,6}, {7,8}
},
{
{9,10}, {11,12}
}
};
这个简单示例中的转换只是颠倒字段顺序,因为两个结构实际上是同一类型。在我的应用程序中,这些是完全不同的类型。
using Foo = struct {
uint32_t a;
uint32_t b;
};
using Bar = struct {
uint32_t c;
uint32_t d;
};
想法是,这个 Bar 结构的一维数组可用于构造 Baz
结构。
我在使用 lambda 转换器时遇到问题。我相信外部的一次占用一行,而内部的一次占用一列,而实际的 Foo->Bar 转换发生。在现场演示中,我不得不注释掉 std::transform 采用二维数组并将其替换为扁平化版本,我将二维数组转换为一维数组(大小为行乘以列)。这工作完美 - 但我试图坚持参数类型而不必求助于 reinterpret_cast<>.
std::vector<Bar> array1d;
array1d.reserve(Baz::gArraySize);
#if 0
// I don't know how to use the transform on the 2d array
std::transform(std::cbegin(array2d), std::cend(array2d),
std::back_inserter(array1d),
[](const Foo(&rRow)[Baz::gNumCols]) {
std::transform(std::cbegin(rRow), std::cend(rRow),
[](const Foo& rNext) -> Bar {
// reverse the order of the fields
return Bar{ rNext.b, rNext.a };
});
});
#else
// Only workaround is to cast the 2d array to a 1d array using reinterpret cast<>
const auto& special = reinterpret_cast<const Foo(&)[Baz::gArraySize]>(array2d);
// I don't know how to use the transform on the 2d array
std::transform(std::cbegin(special), std::cend(special),
std::back_inserter(array1d),
[](const Foo& rNext) -> Bar {
// reverse the order of the fields
return Bar{ rNext.b, rNext.a };
});
#endif
// construct from transformed 2d array
Baz myBaz(reinterpret_cast<const Bar(&)[Baz::gArraySize]>(array1d[0]));
std::cout << myBaz;
生成如下预期输出:
g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
Bar{c=2, d=1},
Bar{c=4, d=3},
Bar{c=6, d=5},
Bar{c=8, d=7},
Bar{c=10, d=9},
Bar{c=12, d=11},
由于这些结构来自外部源,因此结构采用类似于 C 的数组形式。我不确定 std::transform 我想做的事情是否可行,但我想使用 STL 算法而不是手动解开循环。
我创建了以下 live coliru demo 来展示我试图实现的目标 - 但它在适当的转换中出现了很多错误。请注意,传递给 Baz 的数组取决于 std::vector 在内存中连续分配数据结构这一事实(这是由 STL 保证的)。
struct Baz {
constexpr static int gNumRows = 3;
constexpr static int gNumCols = 2;
constexpr static int gArraySize = gNumRows * gNumCols;
Bar arrayField[gArraySize];
// explicit constructor from C style fixed size array.
explicit Baz(const Bar(&rParam)[gArraySize])
: arrayField{}
{
std::memcpy(arrayField, rParam, gArraySize * sizeof(Bar));
}
friend std::ostream& operator<<(
std::ostream& os, const Baz& rhs) {
for (auto next : rhs.arrayField) {
os << "Bar{c=" << next.c << ", d=" << next.d << "},\n";
}
return os;
}
};
你传递给外部 transform
的 lambda 没有 return 任何东西而且它真的不能因为它应该 return one 输入范围(您的二维数组)的每个元素的值。但是该数组的每个元素都有 两个 值,因此 transform
的每次迭代都会产生两个值,而它应该产生一个值,这就是为什么你不能使用 transform
这里
鉴于此,在此处使用简单循环会更容易且可读性更高:
for (auto &&row : array2d)
for (auto &&foo : row)
oneDimArray.push_back(Bar{ foo.b, foo.a });
将 STL 算法留给实际让您的生活更轻松的情况:)。