Reputation: 14829
I am chasing a rabbit down the hole, by trying to figure out the following:
A minified example is shown below:
template <class s_trait>
class state
{
public:
state(s_trait);
private:
state() = default;
friend class boost::serialization::access;
template <typename archive>
void serialize(archive &, const unsigned int);
};
template <class a_trait>
class action
{
public:
action(a_trait);
private:
action() = default;
friend class boost::serialization::access;
template <typename archive>
void serialize(archive &, const unsigned int);
};
template <class state_type, class action_type>
class policy
{
public:
/// ... some public methods
private:
friend class boost::serialization::access;
std::unordered_map<state_class,
std::unordered_map<action_class,
double>> __policies__;
template <typename archive>
void serialize(archive &, const unsigned int);
};
The above skeleton (without the boring details) has the following design issues:
state
cannot be aware of action, if action is to be aware of stateaction
cannot be aware of state
and vice versapolicy
templates the state
and action
on purposeHowever, compiling an app using those classes creates issues arising from std::pair, which seem to stem from boost::serialization::access, which in turn appear to be from the fact that class policy
needs access to the default empty constructors when calling serialize
:
/usr/include/c++/5/bits/stl_pair.h: In instantiation of ‘constexpr std::pair<_T1, _T2>::pair() [with _T1 = const relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >; _T2 = std::unordered_map<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double, relearn::hasher<relearn::action<mu
mbler::action<std::__cxx11::basic_string<char> > > >, std::equal_to<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::allocator<std::pair<const relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double> > >]’:
/usr/include/boost/serialization/access.hpp:132:9: required from ‘static void boost::serialization::access::construct(T*) [with T = std::pair<const relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >, std::unordered_map<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double, rel
earn::hasher<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::equal_to<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::allocator<std::pair<const relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double> > > >]’
/usr/include/boost/serialization/serialization.hpp:93:22: required from ‘void boost::serialization::load_construct_data(Archive&, T*, unsigned int) [with Archive = boost::archive::binary_iarchive; T = std::pair<const relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >, std::unordered_map<relearn::act
ion<mumbler::action<std::__cxx11::basic_string<char> > >, double, relearn::hasher<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::equal_to<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::allocator<std::pair<const relearn::action<mumbler::action<std::__cxx11::b
asic_string<char> > >, double> > > >]’
/usr/include/boost/serialization/serialization.hpp:158:28: required from ‘void boost::serialization::load_construct_data_adl(Archive&, T*, unsigned int) [with Archive = boost::archive::binary_iarchive; T = std::pair<const relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >, std::unordered_map<relearn
::action<mumbler::action<std::__cxx11::basic_string<char> > >, double, relearn::hasher<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::equal_to<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::allocator<std::pair<const relearn::action<mumbler::action<std::__cxx
11::basic_string<char> > >, double> > > >]’
/usr/include/boost/serialization/detail/stack_constructor.hpp:54:54: required from ‘boost::serialization::detail::stack_construct<Archive, T>::stack_construct(Archive&, unsigned int) [with Archive = boost::archive::binary_iarchive; T = std::pair<const relearn::state<mumbler::state<std::__cxx11::basic_string<char> >
>, std::unordered_map<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double, relearn::hasher<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::equal_to<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::allocator<std::pair<const relearn::act
ion<mumbler::action<std::__cxx11::basic_string<char> > >, double> > > >]’
/usr/include/boost/serialization/unordered_map.hpp:45:55: required from ‘void boost::serialization::stl::archive_input_unordered_map<Archive, Container>::operator()(Archive&, Container&, unsigned int) [with Archive = boost::archive::binary_iarchive; Container = std::unordered_map<relearn::state<mumbler::state<std::
__cxx11::basic_string<char> > >, std::unordered_map<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double, relearn::hasher<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::equal_to<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::allocator
<std::pair<const relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double> > >, relearn::hasher<relearn::state<mumbler::state<std::__cxx11::basic_string<char> > > >, std::equal_to<relearn::state<mumbler::state<std::__cxx11::basic_string<char> > > >, std::allocator<std::pair<const relearn::state<mu
mbler::state<std::__cxx11::basic_string<char> > >, std::unordered_map<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double, relearn::hasher<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::equal_to<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >
>, std::allocator<std::pair<const relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double> > > > > >]’
/usr/include/boost/serialization/unordered_collections_load_imp.hpp:66:14: [ skipping 24 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/archive/detail/iserializer.hpp:618:18: required from ‘void boost::archive::load(Archive&, T&) [with Archive = boost::archive::binary_iarchive; T = relearn::policy<relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >, relearn::action<mumbler::action<std::__cxx11::basic_string<char> >
> >]’
/usr/include/boost/archive/detail/common_iarchive.hpp:66:22: required from ‘void boost::archive::detail::common_iarchive<Archive>::load_override(T&, int) [with T = relearn::policy<relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >, relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >
>; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/basic_binary_iarchive.hpp:76:7: required from ‘void boost::archive::basic_binary_iarchive<Archive>::load_override(T&, int) [with T = relearn::policy<relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >, relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >;
Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/binary_iarchive_impl.hpp:62:9: required from ‘void boost::archive::binary_iarchive_impl<Archive, Elem, Tr>::load_override(T&, int) [with T = relearn::policy<relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >, relearn::action<mumbler::action<std::__cxx11::basic_string<char>
> > >; Archive = boost::archive::binary_iarchive; Elem = char; Tr = std::char_traits<char>]’
/usr/include/boost/archive/detail/interface_iarchive.hpp:60:9: required from ‘Archive& boost::archive::detail::interface_iarchive<Archive>::operator>>(T&) [with T = relearn::policy<relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >, relearn::action<mumbler::action<std::__cxx11::basic_string<char> >
> >; Archive = boost::archive::binary_iarchive]’
/home/alex/codez/mumbler/src/agent.cpp:9:11: required from here
/home/alex/codez/mumbler/src/relearn/src/relearn.hpp:90:5: error: ‘relearn::state<state_trait, value_type>::state() [with state_trait = mumbler::state<std::__cxx11::basic_string<char> >; value_type = double]’ is private
state() = default;
As far as I can see, I have two options:
Is there some other way to go around this without exposing public empty constructors?
This is not a duplicate, I know how to (de)serialize, the question is about hiding the default constructor for only the (de)serializer to have access to it.
Upvotes: 1
Views: 153
Reputation: 249093
Make your default constructors protected
, then make a derived class from each that has a public constructor but hide those derived classes from the outside entirely (put them in a detail
header file that nobody else includes). Then your policy
class can use the derived classes internally, for serialization and storage, but only expose them as (sliced) base class objects.
Upvotes: 2