I want to pass a row-major argument list to a constexpr constructor and store the data in a column-major array. I have to transpose the template parameter pack from row-major to column-major and the only way I came up with was by using a temporary array like this:
template <typename T, std::size_t rows, std::size_t cols = rows>
class Matrix final
{
public:
std::array<T, cols * rows> m; // column-major matrix
template <typename ...A>
constexpr Matrix(const A... args) noexcept:
m{transpose(std::array<T, rows * cols>{args...}, std::make_index_sequence<rows * cols>{})}
{}
template <std::size_t ...i>
constexpr auto transpose(const std::array<T, cols * rows> a,
const std::index_sequence<i...>) noexcept
{
return std::array<T, cols * rows>{a[((i % rows) * cols + i / rows)]...};
}
};
I guess there is no other way to access the elements in a parameter-pack out of order, but maybe there is a way to do it without an intermediate array.
To significantly improve the performance of debug builds without removing features, you'll need to replace std::array with a more basic functionless version:
https://quick-bench.com/q/FS2cphByJEWMFMsquI_Yor8ZnyI
The resulting version (ChangedArrayBasic) is ~2.8x faster than the original on Clang 12.0, -O0, libstdc++.
The index operator must not be used since it appears to be largely unoptimizable in practice, instead the internal array needs to be accessed manually.
template <class T, size_t N>
struct BasicCustomArray
{
T d[N];
};
template <typename T, std::size_t rows, std::size_t cols = rows>
class NewMatrixBasic final
{
public:
using Arr = BasicCustomArray<T, cols * rows>; // <-----------------------------
Arr m; // column-major matrix
template <typename ...A>
constexpr NewMatrixBasic(const A... args) noexcept:
m{transpose(Arr{args...}, std::make_index_sequence<rows * cols>{})}
{}
template <std::size_t ...i>
constexpr auto transpose(const Arr a,
const std::index_sequence<i...>) noexcept
{
return Arr{a.d[((i % rows) * cols + i / rows)]...}; // <---------------------
}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With