问题描述
更新:在Google上搜索并阅读了代码中的doxygen注释后,我设法使其正常工作。问题是我在使用 resize()
方法并且没有使用 std :: ios :: binary
之前错过了转换为溪流。如果您想做类似的事情,最好检查一下Azoth的答案。
UPDATED: I managed to get it to work after I googled around and read the doxygen comments in code. Problem was that I missed the cast before using resize()
method and also not using std::ios::binary
for the streams. If you want to do something similar, better check the answer by Azoth.
我正在尝试序列化 Eigen :: Matrix
使用谷类输入。这就是我所拥有的(松散地基于 https://gist.github.com/mtao/5798888以及谷物/类型
)中的类型:
I am trying to serialize Eigen::Matrix
type using Cereal. This is what I have (loosely based on https://gist.github.com/mtao/5798888 and the the types in cereal/types
):
#include <cereal/cereal.hpp>
#include <cereal/archives/binary.hpp>
#include <Eigen/Dense>
#include <fstream>
namespace cereal
{
template <class Archive, class _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> inline
typename std::enable_if<traits::is_output_serializable<BinaryData<_Scalar>, Archive>::value, void>::type
save(Archive & ar, Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> const & m)
{
int rows = m.rows();
int cols = m.cols();
ar(make_size_tag(static_cast<size_type>(rows * cols)));
ar(rows);
ar(cols);
ar(binary_data(m.data(), rows * cols * sizeof(_Scalar)));
}
template <class Archive, class _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> inline
typename std::enable_if<traits::is_input_serializable<BinaryData<_Scalar>, Archive>::value, void>::type
load(Archive & ar, Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> const & m)
{
size_type size;
ar(make_size_tag(size));
int rows;
int cols;
ar(rows);
ar(cols);
const_cast<Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> &>(m).resize(rows, cols);
ar(binary_data(const_cast<_Scalar *>(m.data()), static_cast<std::size_t>(size * sizeof(_Scalar))));
}
}
int main() {
Eigen::MatrixXd test = Eigen::MatrixXd::Random(10, 3);
std::ofstream out = std::ofstream("eigen.cereal", std::ios::binary);
cereal::BinaryOutputArchive archive_o(out);
archive_o(test);
std::cout << "test:" << std::endl << test << std::endl;
out.close();
Eigen::MatrixXd test_loaded;
std::ifstream in = std::ifstream("eigen.cereal", std::ios::binary);
cereal::BinaryInputArchive archive_i(in);
archive_i(test_loaded);
std::cout << "test loaded:" << std::endl << test_loaded << std::endl;
}
推荐答案
您的代码几乎正确,但有一些错误:
Your code is nearly correct but has a few mistakes:
您不需要进行 size_tag
的序列化,因为明确显示行和列。通常,谷物将 size_tag
用于可调整大小的容器,例如矢量或列表。即使矩阵可以调整大小,但仅对行和列进行显式序列化才有意义。
You don't need to be making the size_tag
since you are serializing the number of rows and columns explicitly. Generally cereal uses size_tag
for resizable containers like vectors or lists. Even though the matrix can resize, it makes more sense just to serialize the rows and columns explicitly.
- 您的加载函数应通过非const引用接受其参数
- 您不应使用使用
std :: ofstream
对象 - 更好的做法是让作用域和RAII处理<$的关闭/删除c $ c> std :: ofstream 以及谷物档案(二进制档案将立即清除其内容,但一般而言,谷物档案仅保证在销毁时清除其内容)
- Your load function should accept its parameter by non-const reference
- You shouldn't use operator= with the
std::ofstream
objects - It's better practice to let scoping and RAII handle closing/tearing down of the
std::ofstream
as well as cereal archives (the binary archive will flush its contents immediately, but in general cereal archives are only guaranteed to flush their contents on destruction)
以下是在g ++和clang ++下编译并产生正确输出的版本:
Here's a version that compiles and produces correct output under g++ and clang++:
#include <cereal/cereal.hpp>
#include <cereal/archives/binary.hpp>
#include <Eigen/Dense>
#include <fstream>
namespace cereal
{
template <class Archive, class _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> inline
typename std::enable_if<traits::is_output_serializable<BinaryData<_Scalar>, Archive>::value, void>::type
save(Archive & ar, Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> const & m)
{
int32_t rows = m.rows();
int32_t cols = m.cols();
ar(rows);
ar(cols);
ar(binary_data(m.data(), rows * cols * sizeof(_Scalar)));
}
template <class Archive, class _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> inline
typename std::enable_if<traits::is_input_serializable<BinaryData<_Scalar>, Archive>::value, void>::type
load(Archive & ar, Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> & m)
{
int32_t rows;
int32_t cols;
ar(rows);
ar(cols);
m.resize(rows, cols);
ar(binary_data(m.data(), static_cast<std::size_t>(rows * cols * sizeof(_Scalar))));
}
}
int main() {
Eigen::MatrixXd test = Eigen::MatrixXd::Random(10, 3);
{
std::ofstream out("eigen.cereal", std::ios::binary);
cereal::BinaryOutputArchive archive_o(out);
archive_o(test);
}
std::cout << "test:" << std::endl << test << std::endl;
Eigen::MatrixXd test_loaded;
{
std::ifstream in("eigen.cereal", std::ios::binary);
cereal::BinaryInputArchive archive_i(in);
archive_i(test_loaded);
}
std::cout << "test loaded:" << std::endl << test_loaded << std::endl;
}
这篇关于使用谷类库序列化Eigen :: Matrix的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!