Working on type traits for Boost Transition Layer

This commit is contained in:
Shane Grant
2013-12-02 21:28:48 -08:00
parent 61315b09ec
commit cf64c03335
4 changed files with 165 additions and 4 deletions

View File

@@ -125,6 +125,25 @@ namespace cereal
static auto member_load(Archive & ar, T & t) -> decltype(t.load(ar)) static auto member_load(Archive & ar, T & t) -> decltype(t.load(ar))
{ t.load(ar); } { t.load(ar); }
/*! @name Boost Transition Layer */
//! @{
template<class Archive, class T> inline
static auto member_serialize(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.serialize(ar, version))
{ t.serialize(ar, version); }
template<class Archive, class T> inline
static auto member_save(Archive & ar, T const & t, const std::uint32_t version ) -> decltype(t.save(ar, version))
{ t.save(ar, version); }
template<class Archive, class T> inline
static auto member_save_non_const(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.save(ar, version))
{ t.save(ar, version); }
template<class Archive, class T> inline
static auto member_load(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.load(ar, version))
{ t.load(ar, version); }
//! @}
template <class T> template <class T>
static void load_and_allocate(...) static void load_and_allocate(...)
{ } { }

View File

@@ -309,7 +309,14 @@ namespace cereal
/*! This is part of the Boost Transition Layer and is not the recommended way /*! This is part of the Boost Transition Layer and is not the recommended way
of using cereal. This works identically to how it does in Boost serialization, of using cereal. This works identically to how it does in Boost serialization,
providing a version number associated with some type that is available by specifying providing a version number associated with some type that is available by specifying
a second parameter to serialize, save, or load. */ a second parameter to serialize, save, or load.
If you are using the two parameter versions of serialization functions, a default
value of 0 will be used for version unless you specify otherwise with this macro.
The recommended way of performing versioning in cereal is to implement it yourself
on a class by class basis as required, creating a thin wrapper if you do not have
access to the internals of a class. */
#define CEREAL_CLASS_VERSION(TYPE, VERSION_NUMBER) \ #define CEREAL_CLASS_VERSION(TYPE, VERSION_NUMBER) \
namespace cereal { namespace detail { \ namespace cereal { namespace detail { \
template <> struct Version<TYPE> { static const std::uint32_t version = VERSION_NUMBER; };\ template <> struct Version<TYPE> { static const std::uint32_t version = VERSION_NUMBER; };\

View File

@@ -81,6 +81,44 @@ namespace cereal
template <class T, class A> \ template <class T, class A> \
struct has_non_member_##name : std::integral_constant<bool, detail::has_non_member_##name##_impl<T, A>::value> {}; struct has_non_member_##name : std::integral_constant<bool, detail::has_non_member_##name##_impl<T, A>::value> {};
//! Creates a test for whether a non const member function exists with a version parameter
/*! This creates a class derived from std::integral_constant that will be true if
the type has the proper member function for the given archive. */
#define CEREAL_MAKE_HAS_MEMBER_VERSIONED_TEST(name) \
namespace detail \
{ \
template <class T, class A> \
struct has_member_versioned_##name##_impl \
{ \
template <class TT, class AA> \
static auto test(int) -> decltype( cereal::access::member_##name( std::declval<AA&>(), std::declval<TT&>(), 0 ), yes()); \
template <class, class> \
static no test(...); \
static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value; \
}; \
} /* end namespace detail */ \
template <class T, class A> \
struct has_member_versioned_##name : std::integral_constant<bool, detail::has_member_versioned_##name##_impl<T, A>::value> {};
//! Creates a test for whether a non const non-member function exists with a version parameter
/*! This creates a class derived from std::integral_constant that will be true if
the type has the proper non-member function for the given archive. */
#define CEREAL_MAKE_HAS_NON_MEMBER_VERSIONED_TEST(name) \
namespace detail \
{ \
template <class T, class A> \
struct has_non_member_versioned_##name##_impl \
{ \
template <class TT, class AA> \
static auto test(int) -> decltype( name( std::declval<AA&>(), std::declval<TT&>(), 0 ), yes()); \
template <class, class> \
static no test( ... ); \
static const bool value = std::is_same<decltype( test<T, A>( 0 ) ), yes>::value; \
}; \
} /* end namespace detail */ \
template <class T, class A> \
struct has_non_member_versioned_##name : std::integral_constant<bool, detail::has_non_member_versioned_##name##_impl<T, A>::value> {};
// ###################################################################### // ######################################################################
// Member load_and_allocate // Member load_and_allocate
template<typename T, typename A> template<typename T, typename A>
@@ -104,18 +142,34 @@ namespace cereal
// Member Serialize // Member Serialize
CEREAL_MAKE_HAS_MEMBER_TEST(serialize); CEREAL_MAKE_HAS_MEMBER_TEST(serialize);
// ######################################################################
// Member Serialize (versioned, Boost Transition Layer)
CEREAL_MAKE_HAS_MEMBER_VERSIONED_TEST(serialize);
// ###################################################################### // ######################################################################
// Non Member Serialize // Non Member Serialize
CEREAL_MAKE_HAS_NON_MEMBER_TEST(serialize); CEREAL_MAKE_HAS_NON_MEMBER_TEST(serialize);
// ######################################################################
// Non Member Serialize (versioned, Boost Transition Layer)
CEREAL_MAKE_HAS_NON_MEMBER_VERSIONED_TEST(serialize);
// ###################################################################### // ######################################################################
// Member Load // Member Load
CEREAL_MAKE_HAS_MEMBER_TEST(load); CEREAL_MAKE_HAS_MEMBER_TEST(load);
// ######################################################################
// Member Load (versioned, Boost Transition Layer)
CEREAL_MAKE_HAS_MEMBER_VERSIONED_TEST(load);
// ###################################################################### // ######################################################################
// Non Member Load // Non Member Load
CEREAL_MAKE_HAS_NON_MEMBER_TEST(load); CEREAL_MAKE_HAS_NON_MEMBER_TEST(load);
// ######################################################################
// Non Member Load (versioned, Boost Transition Layer)
CEREAL_MAKE_HAS_NON_MEMBER_VERSIONED_TEST(load);
// ###################################################################### // ######################################################################
// Member Save // Member Save
namespace detail namespace detail
@@ -146,6 +200,36 @@ namespace cereal
"save member functions must always be const" ); "save member functions must always be const" );
}; };
// ######################################################################
// Member Save (versioned, Boost Transition Layer)
namespace detail
{
template <class T, class A>
struct has_member_versioned_save_impl
{
template <class TT, class AA>
static auto test(int) -> decltype( cereal::access::member_save( std::declval<AA&>(), std::declval<TT const &>(), 0 ), yes());
template <class, class>
static no test(...);
static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
template <class TT, class AA>
static auto test2(int) -> decltype( cereal::access::member_save_non_const( std::declval<AA &>(), std::declval<typename std::remove_const<TT>::type&>(), 0 ), yes());
template <class, class>
static no test2(...);
static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value;
};
} // end namespace detail
template <class T, class A>
struct has_member_versioned_save : std::integral_constant<bool, detail::has_member_versioned_save_impl<T, A>::value>
{
typedef typename detail::has_member_versioned_save_impl<T, A> check;
static_assert( check::value || !check::not_const_type,
"cereal detected a versioned non-const save.\n"
"save member functions must always be const" );
};
// ###################################################################### // ######################################################################
// Non-const Member Save // Non-const Member Save
namespace detail namespace detail
@@ -176,6 +260,36 @@ namespace cereal
"save non-member functions must always pass their types as const" ); "save non-member functions must always pass their types as const" );
}; };
// ######################################################################
// Non-const Member Save (versioned, Boost Transition Layer)
namespace detail
{
template <class T, class A>
struct has_non_member_versioned_save_impl
{
template <class TT, class AA>
static auto test(int) -> decltype( save( std::declval<AA&>(), std::declval<TT const &>(), 0 ), yes());
template <class, class>
static no test(...);
static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
template <class TT, class AA>
static auto test2(int) -> decltype( save( std::declval<AA &>(), std::declval<typename std::remove_const<TT>::type&>(), 0 ), yes());
template <class, class>
static no test2(...);
static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value;
};
} // end namespace detail
template <class T, class A>
struct has_non_member_versioned_save : std::integral_constant<bool, detail::has_non_member_versioned_save_impl<T, A>::value>
{
typedef typename detail::has_non_member_versioned_save_impl<T, A> check;
static_assert( check::value || !check::not_const_type,
"cereal detected a non-const type parameter in versioned non-member save.\n"
"save non-member functions must always pass their types as const" );
};
// ###################################################################### // ######################################################################
template <class T, class InputArchive, class OutputArchive> template <class T, class InputArchive, class OutputArchive>
struct has_member_split : std::integral_constant<bool, struct has_member_split : std::integral_constant<bool,

View File

@@ -380,6 +380,26 @@ void test_unordered_loads()
} }
} }
struct BoostTransitionMS
{
BoostTransitionMS( int xx ) : x(xx) {}
int x;
//template <class Archive>
//void serialize( Archive & ar )
//{
// ar( x );
//}
template <class Archive>
void serialize( Archive & ar, const std::uint32_t version )
{
std::cout << "BoostTransitionMS " << version << std::endl;
ar( x );
}
};
// ###################################################################### // ######################################################################
int main() int main()
{ {
@@ -652,7 +672,8 @@ int main()
} }
std::cerr << "-------------------------" << std::endl; std::cerr << "-------------------------" << std::endl;
test_unordered_loads<cereal::XMLInputArchive, cereal::XMLOutputArchive>(); std::cout << cereal::traits::has_member_serialize<BoostTransitionMS, cereal::BinaryOutputArchive>() << std::endl;
std::cout << cereal::traits::has_member_versioned_serialize<BoostTransitionMS, cereal::BinaryOutputArchive>() << std::endl;
return 0; return 0;
} }