I know that the following code can be used to write the data of an Eigen Matrix with datatype as double
to a binary file.
template<class T>
void WriteEigenMatrix(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& m, const char* fileName)
{
std::ofstream outFile(fileName, std::ios_base::out | std::ios_base::binary);
outFile.write(m.data(), m.rows()*m.cols());
outFile.close();`
}
How can I generalize this function to accept other Eigen data types like Eigen::Vector
and Eigen::Array
as inputs?
If I use Eigen::EigenBase
, I know that the function will accept all such data types. However, the problem is that I can no longer use m.data()
, as it is not defined in the base class.
Any suggestion to solve this issue?
If you want to allow only "Dense" objects, you can to it as follows:
template<class Derived>
void WriteEigen(const Eigen::DenseBase<Derived>& dense, const char* fileName) {
std::ofstream outFile(fileName, std::ios_base::out | std::ios_base::binary);
outFile.write(reinterpret_cast<const char*>(dense.derived().data()), dense.rows() * dense.cols());
outFile.close();
}
All dense Matrices (including vector & array) inherit from DenseBase
, calling derived
on DenseBase
will give you back the concrete matrix type.
Or use any Base you like.
After comments from @chtz and @Homer512 this version uses PlainObjectBase
and reshaped
in combination with STL algorithm to write to the file, avoiding reinterpret_cast
to char*
and the possible failure in case innerStride() != 1
.
template<class Derived>
void WriteEigen(const Eigen::PlainObjectBase<Derived>& dense, std::string_view fileName) {
std::ofstream outFile(fileName, std::ios_base::out | std::ios_base::binary);
const auto& reshaped = dense.reshaped();
std::copy(reshaped.begin(), reshaped.end(), std::ostream_iterator<typename Derived::Scalar>(outFile));
}
reshaped()
allows to iterate over all entries in an STL manner see example, which will take care of all possible strides. C++20 ranges allows for the nicer
std::ranges::copy(reshaped, std::ostream_iterator<typename Derived::Scalar>(outFile));
Using std::ostream_iterator
allows to use std::(ranges::)copy
instead of ostream::write()
which operates on bytes. To get the underlying data type of the Eigen object, Dense::Scalar
can be used.