diff --git a/include/cereal/types/polymorphic.hpp b/include/cereal/types/polymorphic.hpp index f7967b13..d3c5a538 100644 --- a/include/cereal/types/polymorphic.hpp +++ b/include/cereal/types/polymorphic.hpp @@ -165,9 +165,35 @@ namespace cereal // ###################################################################### // Pointer serialization for polymorphic types - //! Saving std::shared_ptr for polymorphic types + //! Saving std::shared_ptr for polymorphic types, abstract template inline - typename std::enable_if::value, void>::type + typename std::enable_if::value && std::is_abstract::value, void>::type + save( Archive & ar, std::shared_ptr const & ptr ) + { + if(!ptr) + { + // same behavior as nullptr in memory implementation + ar( _CEREAL_NVP("id", std::uint32_t(0)) ); + return; + } + + std::type_info const & ptrinfo = typeid(*ptr.get()); + // ptrinfo can never be equal to T info since we can't have an instance + // of an abstract object + // this implies we need to do the lookup + + auto & bindingMap = detail::StaticObject>::getInstance().map; + + auto binding = bindingMap.find(std::type_index(ptrinfo)); + if(binding == bindingMap.end()) + throw cereal::Exception("Trying to save an unregistered polymorphic type (" + cereal::util::demangle(ptrinfo.name()) + ")"); + + binding->second.shared_ptr(&ar, ptr.get()); + } + + //! Saving std::shared_ptr for polymorphic types, not abstract + template inline + typename std::enable_if::value && !std::is_abstract::value, void>::type save( Archive & ar, std::shared_ptr const & ptr ) { if(!ptr) @@ -237,9 +263,35 @@ namespace cereal ptr = sptr; } - //! Saving std::unique_ptr for polymorphic types + //! Saving std::unique_ptr for polymorphic types that are abstract template inline - typename std::enable_if::value, void>::type + typename std::enable_if::value && std::is_abstract::value, void>::type + save( Archive & ar, std::unique_ptr const & ptr ) + { + if(!ptr) + { + // same behavior as nullptr in memory implementation + ar( _CEREAL_NVP("id", std::uint32_t(0)) ); + return; + } + + std::type_info const & ptrinfo = typeid(*ptr.get()); + // ptrinfo can never be equal to T info since we can't have an instance + // of an abstract object + // this implies we need to do the lookup + + auto & bindingMap = detail::StaticObject>::getInstance().map; + + auto binding = bindingMap.find(std::type_index(ptrinfo)); + if(binding == bindingMap.end()) + throw cereal::Exception("Trying to save an unregistered polymorphic type (" + cereal::util::demangle(ptrinfo.name()) + ")"); + + binding->second.unique_ptr(&ar, ptr.get()); + } + + //! Saving std::unique_ptr for polymorphic types, not abstract + template inline + typename std::enable_if::value && !std::is_abstract::value, void>::type save( Archive & ar, std::unique_ptr const & ptr ) { if(!ptr) diff --git a/sandbox_rtti.cpp b/sandbox_rtti.cpp index 463ad438..dc5671b5 100644 --- a/sandbox_rtti.cpp +++ b/sandbox_rtti.cpp @@ -173,6 +173,15 @@ struct AAA virtual void foo() = 0; }; +struct BBB : AAA +{ + void foo() {} + template + void serialize( Archive & ) {} +}; + +CEREAL_REGISTER_TYPE(BBB); + template void nop(T&&) {} int main() @@ -193,6 +202,10 @@ int main() //oarchive(ptr3); //oarchive(ptr4); oarchive(ptr5); + + + std::shared_ptr a = std::make_shared(); + oarchive(a); } { @@ -212,6 +225,4 @@ int main() //iarchive(ptr4); iarchive(ptr5); } - - //std::remove("rtti.txt"); }