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))
{ 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>
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
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
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) \
namespace cereal { namespace detail { \
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> \
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
template<typename T, typename A>
@@ -104,18 +142,34 @@ namespace cereal
// Member Serialize
CEREAL_MAKE_HAS_MEMBER_TEST(serialize);
// ######################################################################
// Member Serialize (versioned, Boost Transition Layer)
CEREAL_MAKE_HAS_MEMBER_VERSIONED_TEST(serialize);
// ######################################################################
// Non Member 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
CEREAL_MAKE_HAS_MEMBER_TEST(load);
// ######################################################################
// Member Load (versioned, Boost Transition Layer)
CEREAL_MAKE_HAS_MEMBER_VERSIONED_TEST(load);
// ######################################################################
// Non Member 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
namespace detail
@@ -146,6 +200,36 @@ namespace cereal
"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
namespace detail
@@ -176,6 +260,36 @@ namespace cereal
"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>
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()
{
@@ -652,7 +672,8 @@ int main()
}
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;
}