Una función genérica para almacenar la matriz Eigen en un archivo binario
Sé que el siguiente código se puede utilizar para escribir los datos de una matriz propia con tipo de datos como double
en un archivo binario.
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();`
}
¿Cómo puedo generalizar esta función para aceptar otros tipos de datos propios como Eigen::Vector
y Eigen::Array
como entradas?
Si uso Eigen::EigenBase
, sé que la función aceptará todos esos tipos de datos. Sin embargo, el problema es que ya no puedo usarlo m.data()
, ya que no está definido en la clase base.
¿Alguna sugerencia para resolver este problema?
Si desea permitir sólo objetos "densos", puede hacerlo de la siguiente manera:
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();
}
Todas las matrices densas (incluidos los vectores y las matrices) heredan de DenseBase
, al llamar derived
le DenseBase
devolverán el tipo de matriz concreto.
O usa cualquier Base que quieras.
Después de los comentarios de @chtz y @Homer512, esta versión utiliza PlainObjectBase
y reshaped
en combinación con el algoritmo STL para escribir en el archivo, evitando reinterpret_cast
el char*
posible fallo en caso de que se produzca un error 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()
permite iterar sobre todas las entradas en forma STL ( ver ejemplo) , que se encargará de todos los avances posibles. Los rangos de C++20 permiten mejores
std::ranges::copy(reshaped, std::ostream_iterator<typename Derived::Scalar>(outFile));
El uso std::ostream_iterator
permite utilizar std::(ranges::)copy
en lugar de ostream::write()
which opera en bytes. Para obtener el tipo de datos subyacente del objeto propio, Dense::Scalar
se puede utilizar.