Phi*_*ipp 4 c++ boost stdmap boost-serialization
考虑以下代码:
#include <boost/serialization/nvp.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
class Foo{
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int)
{
ar & BOOST_SERIALIZATION_NVP(i);
}
int i;
Foo():i(0){}
public:
Foo(int k):i(k){}
};
int main(int argc, char *argv[])
{
std::vector< Foo> f;
f.push_back(Foo(12));
std::ofstream os("path");
boost::archive::xml_oarchive oa(os);
oa << boost::serialization::make_nvp("f", f);
os.close();
std::vector<Foo> g;
std::ifstream is("path");
boost::archive::xml_iarchive ia(is);
ia >> boost::serialization::make_nvp("f", g);
}
Run Code Online (Sandbox Code Playgroud)
在序列化 Foos 向量时效果很好。但是,如果我尝试序列化 Foos 的映射,它会在私有默认构造函数上失败:
std::map<std::string, Foo> f;
f.insert(std::make_pair("hello", Foo(12)));
std::ofstream os("path");
boost::archive::xml_oarchive oa(os);
oa << boost::serialization::make_nvp("f", f);
os.close();
std::map<std::string, Foo> g;
std::ifstream is("path");
boost::archive::xml_iarchive ia(is);
ia >> boost::serialization::make_nvp("f", g);
Run Code Online (Sandbox Code Playgroud)
失败了
In file included from main.cpp:2:
In file included from /usr/local/include/boost/serialization/nvp.hpp:19:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/utility:70:
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_pair.h:109:18: error: field of type 'Foo' has private default constructor
: first(), second() { }
^
/usr/local/include/boost/serialization/access.hpp:132:17: note: in instantiation of member function 'std::pair<const std::basic_string<char>, Foo>::pair' requested here
::new(t)T;
^
/usr/local/include/boost/serialization/serialization.hpp:93:13: note: in instantiation of function template specialization 'boost::serialization::access::construct<std::pair<const std::basic_string<char>, Foo> >' requested here
access::construct(t);
^
/usr/local/include/boost/serialization/serialization.hpp:158:9: note: in instantiation of function template specialization 'boost::serialization::load_construct_data<boost::archive::xml_iarchive, std::pair<const std::basic_string<char>, Foo> >' requested here
load_construct_data(ar, t, v);
^
/usr/local/include/boost/serialization/detail/stack_constructor.hpp:58:31: note: in instantiation of function template specialization 'boost::serialization::load_construct_data_adl<boost::archive::xml_iarchive, std::pair<const std::basic_string<char>, Foo> >' requested here
boost::serialization::load_construct_data_adl(
^
/usr/local/include/boost/serialization/collections_load_imp.hpp:83:48: note: in instantiation of member function 'boost::serialization::detail::stack_construct<boost::archive::xml_iarchive, std::pair<const std::basic_string<char>, Foo> >::stack_construct' requested here
detail::stack_construct<Archive, type> t(ar, v);
^
/usr/local/include/boost/serialization/collections_load_imp.hpp:158:16: note: (skipping 12 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
hint = ifunc(ar, s, item_version, hint);
^
/usr/local/include/boost/archive/detail/common_iarchive.hpp:66:18: note: in instantiation of function template specialization 'boost::archive::load<boost::archive::xml_iarchive, std::map<std::basic_string<char>, Foo, std::less<std::basic_string<char> >, std::allocator<std::pair<const std::basic_string<char>, Foo> > > >' requested here
archive::load(* this->This(), t);
^
/usr/local/include/boost/archive/basic_xml_iarchive.hpp:86:39: note: in instantiation of function template specialization 'boost::archive::detail::common_iarchive<boost::archive::xml_iarchive>::load_override<std::map<std::basic_string<char>, Foo, std::less<std::basic_string<char> >, std::allocator<std::pair<const std::basic_string<char>, Foo> > > >' requested here
this->detail_common_iarchive::load_override(t.value(), 0);
^
/usr/local/include/boost/archive/xml_iarchive.hpp:93:38: note: in instantiation of function template specialization 'boost::archive::basic_xml_iarchive<boost::archive::xml_iarchive>::load_override<std::map<std::basic_string<char>, Foo, std::less<std::basic_string<char> >, std::allocator<std::pair<const std::basic_string<char>, Foo> > > >' requested here
basic_xml_iarchive<Archive>::load_override(t, 0);
^
/usr/local/include/boost/archive/detail/interface_iarchive.hpp:60:23: note: in instantiation of function template specialization 'boost::archive::xml_iarchive_impl<boost::archive::xml_iarchive>::load_override<const boost::serialization::nvp<std::map<std::basic_string<char>, Foo, std::less<std::basic_string<char> >, std::allocator<std::pair<const std::basic_string<char>, Foo> > > > >' requested here
this->This()->load_override(t, 0);
^
main.cpp:50:8: note: in instantiation of function template specialization 'boost::archive::detail::interface_iarchive<boost::archive::xml_iarchive>::operator>><const boost::serialization::nvp<std::map<std::basic_string<char>, Foo, std::less<std::basic_string<char> >, std::allocator<std::pair<const std::basic_string<char>, Foo> > > > >' requested here
ia >> boost::serialization::make_nvp("f", g);
^
main.cpp:34:5: note: implicitly declared private here
Foo():i(0){}
^
Run Code Online (Sandbox Code Playgroud)
我正在使用 clang Ubuntu clang 版本 3.4-1ubuntu3 (tags/RELEASE_34/final) (基于 LLVM 3.4)
以及 Ubuntu 14.04LTS 附带的 boost 版本 1.55。
我尝试提供 load_construct_data() 函数,如下所示:
namespace boost
{
namespace serialization
{
template<class Archive>
inline void load_construct_data(Archive &archive, Foo*a, unsigned int
file_version)
{
::new(a)Foo(0);
}
}
}
Run Code Online (Sandbox Code Playgroud)
但我仍然遇到相同的错误,因为它在实例化 std::pair 时需要构造函数
哦。啊哈。
\n\n我刚刚使用 Boost 1.57.0 来比较情况map<string, Foo>。
嗯,你很幸运。您发现了另一个库版本依赖项(可能是一个错误)。
\n\n不使用它,而是提供私有默认构造函数,GCC 4.8.2 可以很好地编译它:Live On Coliru [1]
GCC 4.9.0 无法编译它(它也使用了更新版本的标准库)。默认构造函数std::pair<>无法在那里编译,因为Foo不可默认构造:Live On Coliru
save_construct_data幸运的是,使用/的解决方案 load_construct_data再次挽救了局面。
但是,您需要考虑以下事实:元素类型实际上不是Foo,而是std::pair<T const, Foo>。
template <class Archive, typename K> inline friend void save_construct_data(Archive& ar, std::pair<K, Foo> const* v, const unsigned int) {\n std::cerr << __PRETTY_FUNCTION__ << "\\n";\n ar & boost::serialization::make_nvp("first", v->first);\n ar & boost::serialization::make_nvp("second", v->second.i);\n}\ntemplate <class Archive, typename K> inline friend void load_construct_data(Archive& ar, std::pair<K, Foo>* v, const unsigned int) {\n std::cerr << __PRETTY_FUNCTION__ << "\\n";\n typename std::remove_cv<K>::type first;\n ar & boost::serialization::make_nvp("first", first);\n int tmp;\n ar & boost::serialization::make_nvp("second", tmp);\n new(v) std::pair<K, Foo>(first, tmp);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n现在一切正常了:
\n\n\n\n#include <boost/serialization/nvp.hpp>\n#include <boost/serialization/serialization.hpp>\n#include <boost/archive/xml_iarchive.hpp>\n#include <boost/archive/xml_oarchive.hpp>\n#include <boost/serialization/access.hpp>\n#include <boost/serialization/vector.hpp>\n#include <boost/serialization/map.hpp>\n#include <boost/version.hpp>\n#include <fstream>\n#include <iostream>\n\nclass Foo {\n friend class boost::serialization::access;\n\n template <class Archive> void serialize(Archive &, const unsigned int) {\n std::cerr << __PRETTY_FUNCTION__ << "\\n";\n }\n\n template <class Archive, typename K> inline friend void save_construct_data(Archive& ar, std::pair<K, Foo> const* v, const unsigned int) {\n std::cerr << __PRETTY_FUNCTION__ << "\\n";\n ar & boost::serialization::make_nvp("first", v->first);\n ar & boost::serialization::make_nvp("second", v->second.i);\n }\n template <class Archive, typename K> inline friend void load_construct_data(Archive& ar, std::pair<K, Foo>* v, const unsigned int) {\n std::cerr << __PRETTY_FUNCTION__ << "\\n";\n typename std::remove_cv<K>::type first;\n ar & boost::serialization::make_nvp("first", first);\n int tmp;\n ar & boost::serialization::make_nvp("second", tmp);\n new(v) std::pair<K, Foo>(first, tmp);\n }\n\n int i;\n\n public:\n Foo(int k) : i(k) {}\n\n friend std::ostream& operator<<(std::ostream& os, Foo const& foo) {\n return os << "Foo { " << foo.i << " }";\n }\n};\n\nnamespace boost { namespace serialization {\n\n\n} }\n\nint main() {\n using Data = std::map<std::string, Foo>;\n std::cout << "Boost version: " << BOOST_VERSION << "\\n";\n\n {\n auto f = Data { {"a", 12 }, {"b", 42} };\n //for (auto& e : f) std::cout << e.first << ", " << e.second << "\\n";\n std::ofstream os("path");\n boost::archive::xml_oarchive oa(os);\n oa << boost::serialization::make_nvp("f", f);\n }\n\n {\n Data g;\n std::ifstream is("path");\n boost::archive::xml_iarchive ia(is);\n ia >> boost::serialization::make_nvp("f", g);\n\n for (auto& e : g)\n std::cout << e.first << ", " << e.second << "\\n";\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n哪个打印:
\n\nBoost version: 105700\nvoid save_construct_data(Archive&, const std::pair<K, Foo>*, unsigned int) [with Archive = boost::archive::xml_oarchive; K = const std::__cxx11::basic_string<char>]\nvoid Foo::serialize(Archive&, unsigned int) [with Archive = boost::archive::xml_oarchive]\nvoid save_construct_data(Archive&, const std::pair<K, Foo>*, unsigned int) [with Archive = boost::archive::xml_oarchive; K = const std::__cxx11::basic_string<char>]\nvoid Foo::serialize(Archive&, unsigned int) [with Archive = boost::archive::xml_oarchive]\nvoid load_construct_data(Archive&, std::pair<K, Foo>*, unsigned int) [with Archive = boost::archive::xml_iarchive; K = const std::__cxx11::basic_string<char>]\nvoid Foo::serialize(Archive&, unsigned int) [with Archive = boost::archive::xml_iarchive]\nvoid load_construct_data(Archive&, std::pair<K, Foo>*, unsigned int) [with Archive = boost::archive::xml_iarchive; K = const std::__cxx11::basic_string<char>]\nvoid Foo::serialize(Archive&, unsigned int) [with Archive = boost::archive::xml_iarchive]\na, Foo { 12 }\nb, Foo { 42 }\nRun Code Online (Sandbox Code Playgroud)\n\n[1](我无法在 Coliru 上链接它,因为那里的 boost 库已被重新编译为 GCC 5.0 ABI)
\n\n更好的通用解决方案是load/save_construct_data对命名空间中的非默认可构造类型进行通用处理boost::serialization。这样,人们就不必“了解”std::pair<>实施细节。他们可以只load/save_construct_data为自己的用户类型实现,无论他们将其放入向量还是地图中,都将 JustWork\xe2\x84\xa2 。
不过,实现这一点通常并不简单,并且可能会干扰 Boost Serialization 框架内部的一些其他机制。
\n\n我更愿意得到 Boost Serialization 维护人员的帮助,以可靠的方式做到这一点。所以,看来我今天要提交两张票。
\n| 归档时间: |
|
| 查看次数: |
1827 次 |
| 最近记录: |