LCOV - code coverage report

Current view: | top level - cereal/details - traits.hpp (source / functions) |  |  | Hit | Total | Coverage
Test: | coverage.info |  | Lines: | 22 | 22 | 100.0 %
Date: | 2022-01-16 21:05:07 |  | Functions: | 67 | 71 | 94.4 %

              Line data    Source code

           1             : /*! \file traits.hpp
           2             :     \brief Internal type trait support
           3             :     \ingroup Internal */
           4             : /*
           5             :   Copyright (c) 2014, Randolph Voorhies, Shane Grant
           6             :   All rights reserved.
           7             :
           8             :   Redistribution and use in source and binary forms, with or without
           9             :   modification, are permitted provided that the following conditions are met:
          10             :       * Redistributions of source code must retain the above copyright
          11             :         notice, this list of conditions and the following disclaimer.
          12             :       * Redistributions in binary form must reproduce the above copyright
          13             :         notice, this list of conditions and the following disclaimer in the
          14             :         documentation and/or other materials provided with the distribution.
          15             :       * Neither the name of the copyright holder nor the
          16             :         names of its contributors may be used to endorse or promote products
          17             :         derived from this software without specific prior written permission.
          18             :
          19             :   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
          20             :   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
          21             :   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
          22             :   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
          23             :   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
          24             :   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
          25             :   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
          26             :   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
          27             :   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
          28             :   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
          29             : */
          30             : #ifndef CEREAL_DETAILS_TRAITS_HPP_
          31             : #define CEREAL_DETAILS_TRAITS_HPP_
          32             :
          33             : #ifndef __clang__
          34             : #if (__GNUC__ == 4 && __GNUC_MINOR__ <= 7)
          35             : #define CEREAL_OLDER_GCC
          36             : #endif // gcc 4.7 or earlier
          37             : #endif // __clang__
          38             :
          39             : #include <type_traits>
          40             : #include <typeindex>
          41             :
          42             : #include "cereal/macros.hpp"
          43             : #include "cereal/access.hpp"
          44             :
          45             : namespace cereal
          46             : {
          47             :   namespace traits
          48             :   {
          49             :     using yes = std::true_type;
          50             :     using no  = std::false_type;
          51             :
          52             :     namespace detail
          53             :     {
          54             :       // ######################################################################
          55             :       //! Used to delay a static_assert until template instantiation
          56             :       template <class T>
          57             :       struct delay_static_assert : std::false_type {};
          58             :
          59             :       // ######################################################################
          60             :       // SFINAE Helpers
          61             :       #ifdef CEREAL_OLDER_GCC // when VS supports better SFINAE, we can use this as the default
          62             :       template<typename> struct Void { typedef void type; };
          63             :       #endif // CEREAL_OLDER_GCC
          64             :
          65             :       //! Return type for SFINAE Enablers
          66             :       enum class sfinae {};
          67             :
          68             :       // ######################################################################
          69             :       // Helper functionality for boolean integral constants and Enable/DisableIf
          70             :       template <bool H, bool ... T> struct meta_bool_and : std::integral_constant<bool, H && meta_bool_and<T...>::value> {};
          71             :       template <bool B> struct meta_bool_and<B> : std::integral_constant<bool, B> {};
          72             :
          73             :       template <bool H, bool ... T> struct meta_bool_or : std::integral_constant<bool, H || meta_bool_or<T...>::value> {};
          74             :       template <bool B> struct meta_bool_or<B> : std::integral_constant<bool, B> {};
          75             :
          76             :       // workaround needed due to bug in MSVC 2013, see
          77             :       // http://connect.microsoft.com/VisualStudio/feedback/details/800231/c-11-alias-template-issue
          78             :       template <bool ... Conditions>
          79             :       struct EnableIfHelper : std::enable_if<meta_bool_and<Conditions...>::value, sfinae> {};
          80             :
          81             :       template <bool ... Conditions>
          82             :       struct DisableIfHelper : std::enable_if<!meta_bool_or<Conditions...>::value, sfinae> {};
          83             :     } // namespace detail
          84             :
          85             :     //! Used as the default value for EnableIf and DisableIf template parameters
          86             :     /*! @relates EnableIf
          87             :         @relates DisableIf */
          88             :     static const detail::sfinae sfinae = {};
          89             :
          90             :     // ######################################################################
          91             :     //! Provides a way to enable a function if conditions are met
          92             :     /*! This is intended to be used in a near identical fashion to std::enable_if
          93             :         while being significantly easier to read at the cost of not allowing for as
          94             :         complicated of a condition.
          95             :
          96             :         This will compile (allow the function) if every condition evaluates to true.
          97             :         at compile time.  This should be used with SFINAE to ensure that at least
          98             :         one other candidate function works when one fails due to an EnableIf.
          99             :
         100             :         This should be used as the las template parameter to a function as
         101             :         an unnamed parameter with a default value of cereal::traits::sfinae:
         102             :
         103             :         @code{cpp}
         104             :         // using by making the last template argument variadic
         105             :         template <class T, EnableIf<std::is_same<T, bool>::value> = sfinae>
         106             :         void func(T t );
         107             :         @endcode
         108             :
         109             :         Note that this performs a logical AND of all conditions, so you will need
         110             :         to construct more complicated requirements with this fact in mind.
         111             :
         112             :         @relates DisableIf
         113             :         @relates sfinae
         114             :         @tparam Conditions The conditions which will be logically ANDed to enable the function. */
         115             :     template <bool ... Conditions>
         116             :     using EnableIf = typename detail::EnableIfHelper<Conditions...>::type;
         117             :
         118             :     // ######################################################################
         119             :     //! Provides a way to disable a function if conditions are met
         120             :     /*! This is intended to be used in a near identical fashion to std::enable_if
         121             :         while being significantly easier to read at the cost of not allowing for as
         122             :         complicated of a condition.
         123             :
         124             :         This will compile (allow the function) if every condition evaluates to false.
         125             :         This should be used with SFINAE to ensure that at least one other candidate
         126             :         function works when one fails due to a DisableIf.
         127             :
         128             :         This should be used as the las template parameter to a function as
         129             :         an unnamed parameter with a default value of cereal::traits::sfinae:
         130             :
         131             :         @code{cpp}
         132             :         // using by making the last template argument variadic
         133             :         template <class T, DisableIf<std::is_same<T, bool>::value> = sfinae>
         134             :         void func(T t );
         135             :         @endcode
         136             :
         137             :         This is often used in conjunction with EnableIf to form an enable/disable pair of
         138             :         overloads.
         139             :
         140             :         Note that this performs a logical AND of all conditions, so you will need
         141             :         to construct more complicated requirements with this fact in mind.  If all conditions
         142             :         hold, the function will be disabled.
         143             :
         144             :         @relates EnableIf
         145             :         @relates sfinae
         146             :         @tparam Conditions The conditions which will be logically ANDed to disable the function. */
         147             :     template <bool ... Conditions>
         148             :     using DisableIf = typename detail::DisableIfHelper<Conditions...>::type;
         149             :
         150             :     // ######################################################################
         151             :     namespace detail
         152             :     {
         153             :       template <class InputArchive>
         154             :       struct get_output_from_input : no
         155             :       {
         156             :         static_assert( detail::delay_static_assert<InputArchive>::value,
         157             :             "Could not find an associated output archive for input archive." );
         158             :       };
         159             :
         160             :       template <class OutputArchive>
         161             :       struct get_input_from_output : no
         162             :       {
         163             :         static_assert( detail::delay_static_assert<OutputArchive>::value,
         164             :             "Could not find an associated input archive for output archive." );
         165             :       };
         166             :     }
         167             :
         168             :     //! Sets up traits that relate an input archive to an output archive
         169             :     #define CEREAL_SETUP_ARCHIVE_TRAITS(InputArchive, OutputArchive)  \
         170             :     namespace cereal { namespace traits { namespace detail {          \
         171             :       template <> struct get_output_from_input<InputArchive>          \
         172             :       { using type = OutputArchive; };                                \
         173             :       template <> struct get_input_from_output<OutputArchive>         \
         174             :       { using type = InputArchive; }; } } } /* end namespaces */
         175             :
         176             :     // ######################################################################
         177             :     //! Used to convert a MAKE_HAS_XXX macro into a versioned variant
         178             :     #define CEREAL_MAKE_VERSIONED_TEST ,0
         179             :
         180             :     // ######################################################################
         181             :     //! Creates a test for whether a non const member function exists
         182             :     /*! This creates a class derived from std::integral_constant that will be true if
         183             :         the type has the proper member function for the given archive.
         184             :
         185             :         @param name The name of the function to test for (e.g. serialize, load, save)
         186             :         @param test_name The name to give the test for the function being tested for (e.g. serialize, versioned_serialize)
         187             :         @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
         188             :     #ifdef CEREAL_OLDER_GCC
         189             :     #define CEREAL_MAKE_HAS_MEMBER_TEST(name, test_name, versioned)                                                                         \
         190             :     template <class T, class A, class SFINAE = void>                                                                                        \
         191             :     struct has_member_##test_name : no {};                                                                                                  \
         192             :     template <class T, class A>                                                                                                             \
         193             :     struct has_member_##test_name<T, A,                                                                                                     \
         194             :       typename detail::Void< decltype( cereal::access::member_##name( std::declval<A&>(), std::declval<T&>() versioned ) ) >::type> : yes {}
         195             :     #else // NOT CEREAL_OLDER_GCC
         196             :     #define CEREAL_MAKE_HAS_MEMBER_TEST(name, test_name, versioned)                                                                     \
         197             :     namespace detail                                                                                                                    \
         198             :     {                                                                                                                                   \
         199             :       template <class T, class A>                                                                                                       \
         200             :       struct has_member_##name##_##versioned##_impl                                                                                     \
         201             :       {                                                                                                                                 \
         202             :         template <class TT, class AA>                                                                                                   \
         203             :         static auto test(int) -> decltype( cereal::access::member_##name( std::declval<AA&>(), std::declval<TT&>() versioned ), yes()); \
         204             :         template <class, class>                                                                                                         \
         205             :         static no test(...);                                                                                                            \
         206             :         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;                                                    \
         207             :       };                                                                                                                                \
         208             :     } /* end namespace detail */                                                                                                        \
         209             :     template <class T, class A>                                                                                                         \
         210             :     struct has_member_##test_name : std::integral_constant<bool, detail::has_member_##name##_##versioned##_impl<T, A>::value> {}
         211             :     #endif // NOT CEREAL_OLDER_GCC
         212             :
         213             :     // ######################################################################
         214             :     //! Creates a test for whether a non const non-member function exists
         215             :     /*! This creates a class derived from std::integral_constant that will be true if
         216             :         the type has the proper non-member function for the given archive. */
         217             :     #define CEREAL_MAKE_HAS_NON_MEMBER_TEST(test_name, func, versioned)                                                         \
         218             :     namespace detail                                                                                                            \
         219             :     {                                                                                                                           \
         220             :       template <class T, class A>                                                                                               \
         221             :       struct has_non_member_##test_name##_impl                                                                                  \
         222             :       {                                                                                                                         \
         223             :         template <class TT, class AA>                                                                                           \
         224             :         static auto test(int) -> decltype( func( std::declval<AA&>(), std::declval<TT&>() versioned ), yes());                  \
         225             :         template <class, class>                                                                                                 \
         226             :         static no test( ... );                                                                                                  \
         227             :         static const bool value = std::is_same<decltype( test<T, A>( 0 ) ), yes>::value;                                        \
         228             :       };                                                                                                                        \
         229             :     } /* end namespace detail */                                                                                                \
         230             :     template <class T, class A>                                                                                                 \
         231             :     struct has_non_member_##test_name : std::integral_constant<bool, detail::has_non_member_##test_name##_impl<T, A>::value> {}
         232             :
         233             :     // ######################################################################
         234             :     // Member Serialize
         235             :     CEREAL_MAKE_HAS_MEMBER_TEST(serialize, serialize,);
         236             :
         237             :     // ######################################################################
         238             :     // Member Serialize (versioned)
         239             :     CEREAL_MAKE_HAS_MEMBER_TEST(serialize, versioned_serialize, CEREAL_MAKE_VERSIONED_TEST);
         240             :
         241             :     // ######################################################################
         242             :     // Non Member Serialize
         243             :     CEREAL_MAKE_HAS_NON_MEMBER_TEST(serialize, CEREAL_SERIALIZE_FUNCTION_NAME,);
         244             :
         245             :     // ######################################################################
         246             :     // Non Member Serialize (versioned)
         247             :     CEREAL_MAKE_HAS_NON_MEMBER_TEST(versioned_serialize, CEREAL_SERIALIZE_FUNCTION_NAME, CEREAL_MAKE_VERSIONED_TEST);
         248             :
         249             :     // ######################################################################
         250             :     // Member Load
         251             :     CEREAL_MAKE_HAS_MEMBER_TEST(load, load,);
         252             :
         253             :     // ######################################################################
         254             :     // Member Load (versioned)
         255             :     CEREAL_MAKE_HAS_MEMBER_TEST(load, versioned_load, CEREAL_MAKE_VERSIONED_TEST);
         256             :
         257             :     // ######################################################################
         258             :     // Non Member Load
         259             :     CEREAL_MAKE_HAS_NON_MEMBER_TEST(load, CEREAL_LOAD_FUNCTION_NAME,);
         260             :
         261             :     // ######################################################################
         262             :     // Non Member Load (versioned)
         263             :     CEREAL_MAKE_HAS_NON_MEMBER_TEST(versioned_load, CEREAL_LOAD_FUNCTION_NAME, CEREAL_MAKE_VERSIONED_TEST);
         264             :
         265             :     // ######################################################################
         266             :     #undef CEREAL_MAKE_HAS_NON_MEMBER_TEST
         267             :     #undef CEREAL_MAKE_HAS_MEMBER_TEST
         268             :
         269             :     // ######################################################################
         270             :     //! Creates a test for whether a member save function exists
         271             :     /*! This creates a class derived from std::integral_constant that will be true if
         272             :         the type has the proper member function for the given archive.
         273             :
         274             :         @param test_name The name to give the test (e.g. save or versioned_save)
         275             :         @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
         276             :     #ifdef CEREAL_OLDER_GCC
         277             :     #define CEREAL_MAKE_HAS_MEMBER_SAVE_IMPL(test_name, versioned)                                                                  \
         278             :     namespace detail                                                                                                                \
         279             :     {                                                                                                                               \
         280             :     template <class T, class A>                                                                                                     \
         281             :     struct has_member_##test_name##_impl                                                                                            \
         282             :       {                                                                                                                             \
         283             :         template <class TT, class AA, class SFINAE = void> struct test : no {};                                                     \
         284             :         template <class TT, class AA>                                                                                               \
         285             :         struct test<TT, AA,                                                                                                         \
         286             :           typename detail::Void< decltype( cereal::access::member_save( std::declval<AA&>(),                                        \
         287             :                                                                         std::declval<TT const &>() versioned ) ) >::type> : yes {}; \
         288             :         static const bool value = test<T, A>();                                                                                     \
         289             :                                                                                                                                     \
         290             :         template <class TT, class AA, class SFINAE = void> struct test2 : no {};                                                    \
         291             :         template <class TT, class AA>                                                                                               \
         292             :         struct test2<TT, AA,                                                                                                        \
         293             :           typename detail::Void< decltype( cereal::access::member_save_non_const(                                                   \
         294             :                                             std::declval<AA&>(),                                                                    \
         295             :                                             std::declval<typename std::remove_const<TT>::type&>() versioned ) ) >::type> : yes {};  \
         296             :         static const bool not_const_type = test2<T, A>();                                                                           \
         297             :       };                                                                                                                            \
         298             :     } /* end namespace detail */
         299             :     #else /* NOT CEREAL_OLDER_GCC =================================== */
         300             :     #define CEREAL_MAKE_HAS_MEMBER_SAVE_IMPL(test_name, versioned)                                                                  \
         301             :     namespace detail                                                                                                                \
         302             :     {                                                                                                                               \
         303             :     template <class T, class A>                                                                                                     \
         304             :     struct has_member_##test_name##_impl                                                                                            \
         305             :       {                                                                                                                             \
         306             :         template <class TT, class AA>                                                                                               \
         307             :         static auto test(int) -> decltype( cereal::access::member_save( std::declval<AA&>(),                                        \
         308             :                                                                         std::declval<TT const &>() versioned ), yes());             \
         309             :         template <class, class> static no test(...);                                                                                \
         310             :         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;                                                \
         311             :                                                                                                                                     \
         312             :         template <class TT, class AA>                                                                                               \
         313             :         static auto test2(int) -> decltype( cereal::access::member_save_non_const(                                                  \
         314             :                                               std::declval<AA &>(),                                                                 \
         315             :                                               std::declval<typename std::remove_const<TT>::type&>() versioned ), yes());            \
         316             :         template <class, class> static no test2(...);                                                                               \
         317             :         static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value;                                      \
         318             :       };                                                                                                                            \
         319             :     } /* end namespace detail */
         320             :     #endif /* NOT CEREAL_OLDER_GCC */
         321             :
         322             :     // ######################################################################
         323             :     // Member Save
         324             :     CEREAL_MAKE_HAS_MEMBER_SAVE_IMPL(save, )
         325             :
         326             :     template <class T, class A>
         327             :     struct has_member_save : std::integral_constant<bool, detail::has_member_save_impl<T, A>::value>
         328             :     {
         329             :       typedef typename detail::has_member_save_impl<T, A> check;
         330             :       static_assert( check::value || !check::not_const_type,
         331             :         "cereal detected a non-const save. \n "
         332             :         "save member functions must always be const" );
         333             :     };
         334             :
         335             :     // ######################################################################
         336             :     // Member Save (versioned)
         337             :     CEREAL_MAKE_HAS_MEMBER_SAVE_IMPL(versioned_save, CEREAL_MAKE_VERSIONED_TEST)
         338             :
         339             :     template <class T, class A>
         340             :     struct has_member_versioned_save : std::integral_constant<bool, detail::has_member_versioned_save_impl<T, A>::value>
         341             :     {
         342             :       typedef typename detail::has_member_versioned_save_impl<T, A> check;
         343             :       static_assert( check::value || !check::not_const_type,
         344             :         "cereal detected a versioned non-const save. \n "
         345             :         "save member functions must always be const" );
         346             :     };
         347             :
         348             :     // ######################################################################
         349             :     #undef CEREAL_MAKE_HAS_MEMBER_SAVE_IMPL
         350             :
         351             :     // ######################################################################
         352             :     //! Creates a test for whether a non-member save function exists
         353             :     /*! This creates a class derived from std::integral_constant that will be true if
         354             :         the type has the proper non-member function for the given archive.
         355             :
         356             :         @param test_name The name to give the test (e.g. save or versioned_save)
         357             :         @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
         358             :     #define CEREAL_MAKE_HAS_NON_MEMBER_SAVE_TEST(test_name, versioned)                                                       \
         359             :     namespace detail                                                                                                         \
         360             :     {                                                                                                                        \
         361             :       template <class T, class A>                                                                                            \
         362             :       struct has_non_member_##test_name##_impl                                                                               \
         363             :       {                                                                                                                      \
         364             :         template <class TT, class AA>                                                                                        \
         365             :         static auto test(int) -> decltype( CEREAL_SAVE_FUNCTION_NAME(                                                        \
         366             :                                               std::declval<AA&>(),                                                           \
         367             :                                               std::declval<TT const &>() versioned ), yes());                                \
         368             :         template <class, class> static no test(...);                                                                         \
         369             :         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;                                         \
         370             :                                                                                                                              \
         371             :         template <class TT, class AA>                                                                                        \
         372             :         static auto test2(int) -> decltype( CEREAL_SAVE_FUNCTION_NAME(                                                       \
         373             :                                               std::declval<AA &>(),                                                          \
         374             :                                               std::declval<typename std::remove_const<TT>::type&>() versioned ), yes());     \
         375             :         template <class, class> static no test2(...);                                                                        \
         376             :         static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value;                               \
         377             :       };                                                                                                                     \
         378             :     } /* end namespace detail */                                                                                             \
         379             :                                                                                                                              \
         380             :     template <class T, class A>                                                                                              \
         381             :     struct has_non_member_##test_name : std::integral_constant<bool, detail::has_non_member_##test_name##_impl<T, A>::value> \
         382             :     {                                                                                                                        \
         383             :       using check = typename detail::has_non_member_##test_name##_impl<T, A>;                                                \
         384             :       static_assert( check::value || !check::not_const_type,                                                                 \
         385             :         "cereal detected a non-const type parameter in non-member " #test_name ". \n "                                       \
         386             :         #test_name " non-member functions must always pass their types as const" );                                          \
         387             :     };
         388             :
         389             :     // ######################################################################
         390             :     // Non Member Save
         391             :     CEREAL_MAKE_HAS_NON_MEMBER_SAVE_TEST(save, )
         392             :
         393             :     // ######################################################################
         394             :     // Non Member Save (versioned)
         395             :     CEREAL_MAKE_HAS_NON_MEMBER_SAVE_TEST(versioned_save, CEREAL_MAKE_VERSIONED_TEST)
         396             :
         397             :     // ######################################################################
         398             :     #undef CEREAL_MAKE_HAS_NON_MEMBER_SAVE_TEST
         399             :
         400             :     // ######################################################################
         401             :     // Minimal Utilities
         402             :     namespace detail
         403             :     {
         404             :       // Determines if the provided type is an std::string
         405             :       template <class> struct is_string : std::false_type {};
         406             :
         407             :       template <class CharT, class Traits, class Alloc>
         408             :       struct is_string<std::basic_string<CharT, Traits, Alloc>> : std::true_type {};
         409             :     }
         410             :
         411             :     // Determines if the type is valid for use with a minimal serialize function
         412             :     template <class T>
         413             :     struct is_minimal_type : std::integral_constant<bool,
         414             :       detail::is_string<T>::value || std::is_arithmetic<T>::value> {};
         415             :
         416             :     // ######################################################################
         417             :     //! Creates implementation details for whether a member save_minimal function exists
         418             :     /*! This creates a class derived from std::integral_constant that will be true if
         419             :         the type has the proper member function for the given archive.
         420             :
         421             :         @param test_name The name to give the test (e.g. save_minimal or versioned_save_minimal)
         422             :         @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
         423             :     #ifdef CEREAL_OLDER_GCC
         424             :     #define CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_IMPL(test_name, versioned)                                                                        \
         425             :     namespace detail                                                                                                                              \
         426             :     {                                                                                                                                             \
         427             :       template <class T, class A>                                                                                                                 \
         428             :       struct has_member_##test_name##_impl                                                                                                        \
         429             :       {                                                                                                                                           \
         430             :         template <class TT, class AA, class SFINAE = void> struct test : no {};                                                                   \
         431             :         template <class TT, class AA>                                                                                                             \
         432             :         struct test<TT, AA, typename detail::Void< decltype(                                                                                      \
         433             :             cereal::access::member_save_minimal( std::declval<AA const &>(),                                                                      \
         434             :                                                  std::declval<TT const &>() versioned ) ) >::type> : yes {};                                      \
         435             :                                                                                                                                                   \
         436             :         static const bool value = test<T, A>();                                                                                                   \
         437             :                                                                                                                                                   \
         438             :         template <class TT, class AA, class SFINAE = void> struct test2 : no {};                                                                  \
         439             :         template <class TT, class AA>                                                                                                             \
         440             :         struct test2<TT, AA, typename detail::Void< decltype(                                                                                     \
         441             :             cereal::access::member_save_minimal_non_const( std::declval<AA const &>(),                                                            \
         442             :                                                            std::declval<typename std::remove_const<TT>::type&>() versioned ) ) >::type> : yes {}; \
         443             :         static const bool not_const_type = test2<T, A>();                                                                                         \
         444             :                                                                                                                                                   \
         445             :         static const bool valid = value || !not_const_type;                                                                                       \
         446             :       };                                                                                                                                          \
         447             :     } /* end namespace detail */
         448             :     #else /* NOT CEREAL_OLDER_GCC =================================== */
         449             :     #define CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_IMPL(test_name, versioned)                     \
         450             :     namespace detail                                                                           \
         451             :     {                                                                                          \
         452             :       template <class T, class A>                                                              \
         453             :       struct has_member_##test_name##_impl                                                     \
         454             :       {                                                                                        \
         455             :         template <class TT, class AA>                                                          \
         456             :         static auto test(int) -> decltype( cereal::access::member_save_minimal(                \
         457             :               std::declval<AA const &>(),                                                      \
         458             :               std::declval<TT const &>() versioned ), yes());                                  \
         459             :         template <class, class> static no test(...);                                           \
         460             :         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;           \
         461             :                                                                                                \
         462             :         template <class TT, class AA>                                                          \
         463             :         static auto test2(int) -> decltype( cereal::access::member_save_minimal_non_const(     \
         464             :               std::declval<AA const &>(),                                                      \
         465             :               std::declval<typename std::remove_const<TT>::type&>() versioned ), yes());       \
         466             :         template <class, class> static no test2(...);                                          \
         467             :         static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value; \
         468             :                                                                                                \
         469             :         static const bool valid = value || !not_const_type;                                    \
         470             :       };                                                                                       \
         471             :     } /* end namespace detail */
         472             :     #endif // NOT CEREAL_OLDER_GCC
         473             :
         474             :     // ######################################################################
         475             :     //! Creates helpers for minimal save functions
         476             :     /*! The get_member_*_type structs allow access to the return type of a save_minimal,
         477             :         assuming that the function actually exists.  If the function does not
         478             :         exist, the type will be void.
         479             :
         480             :         @param test_name The name to give the test (e.g. save_minimal or versioned_save_minimal)
         481             :         @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
         482             :     #define CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_HELPERS_IMPL(test_name, versioned)                           \
         483             :     namespace detail                                                                                         \
         484             :     {                                                                                                        \
         485             :       template <class T, class A, bool Valid>                                                                \
         486             :       struct get_member_##test_name##_type { using type = void; };                                           \
         487             :                                                                                                              \
         488             :       template <class T, class A>                                                                            \
         489             :       struct get_member_##test_name##_type<T, A, true>                                                       \
         490             :       {                                                                                                      \
         491             :         using type = decltype( cereal::access::member_save_minimal( std::declval<A const &>(),               \
         492             :                                                                     std::declval<T const &>() versioned ) ); \
         493             :       };                                                                                                     \
         494             :     } /* end namespace detail */
         495             :
         496             :     // ######################################################################
         497             :     //! Creates a test for whether a member save_minimal function exists
         498             :     /*! This creates a class derived from std::integral_constant that will be true if
         499             :         the type has the proper member function for the given archive.
         500             :
         501             :         @param test_name The name to give the test (e.g. save_minimal or versioned_save_minimal) */
         502             :     #define CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_TEST(test_name)                                                      \
         503             :     template <class T, class A>                                                                                      \
         504             :     struct has_member_##test_name : std::integral_constant<bool, detail::has_member_##test_name##_impl<T, A>::value> \
         505             :     {                                                                                                                \
         506             :       using check = typename detail::has_member_##test_name##_impl<T, A>;                                            \
         507             :       static_assert( check::valid,                                                                                   \
         508             :         "cereal detected a non-const member " #test_name ". \n "                                                     \
         509             :         #test_name " member functions must always be const" );                                                       \
         510             :                                                                                                                      \
         511             :       using type = typename detail::get_member_##test_name##_type<T, A, check::value>::type;                         \
         512             :       static_assert( (check::value && is_minimal_type<type>::value) || !check::value,                                \
         513             :         "cereal detected a member " #test_name " with an invalid return type. \n "                                   \
         514             :         "return type must be arithmetic or string" );                                                                \
         515             :     };
         516             :
         517             :     // ######################################################################
         518             :     // Member Save Minimal
         519             :     CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_IMPL(save_minimal, )
         520             :     CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_HELPERS_IMPL(save_minimal, )
         521             :     CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_TEST(save_minimal)
         522             :
         523             :     // ######################################################################
         524             :     // Member Save Minimal (versioned)
         525             :     CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_IMPL(versioned_save_minimal, CEREAL_MAKE_VERSIONED_TEST)
         526             :     CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_HELPERS_IMPL(versioned_save_minimal, CEREAL_MAKE_VERSIONED_TEST)
         527             :     CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_TEST(versioned_save_minimal)
         528             :
         529             :     // ######################################################################
         530             :     #undef CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_IMPL
         531             :     #undef CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_HELPERS_IMPL
         532             :     #undef CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_TEST
         533             :
         534             :     // ######################################################################
         535             :     //! Creates a test for whether a non-member save_minimal function exists
         536             :     /*! This creates a class derived from std::integral_constant that will be true if
         537             :         the type has the proper member function for the given archive.
         538             :
         539             :         @param test_name The name to give the test (e.g. save_minimal or versioned_save_minimal)
         540             :         @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
         541             :     #define CEREAL_MAKE_HAS_NON_MEMBER_SAVE_MINIMAL_TEST(test_name, versioned)                                               \
         542             :     namespace detail                                                                                                         \
         543             :     {                                                                                                                        \
         544             :       template <class T, class A>                                                                                            \
         545             :       struct has_non_member_##test_name##_impl                                                                               \
         546             :       {                                                                                                                      \
         547             :         template <class TT, class AA>                                                                                        \
         548             :         static auto test(int) -> decltype( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(                                                \
         549             :               std::declval<AA const &>(),                                                                                    \
         550             :               std::declval<TT const &>() versioned ), yes());                                                                \
         551             :         template <class, class> static no test(...);                                                                         \
         552             :         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;                                         \
         553             :                                                                                                                              \
         554             :         template <class TT, class AA>                                                                                        \
         555             :         static auto test2(int) -> decltype( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(                                               \
         556             :               std::declval<AA const &>(),                                                                                    \
         557             :               std::declval<typename std::remove_const<TT>::type&>() versioned ), yes());                                     \
         558             :         template <class, class> static no test2(...);                                                                        \
         559             :         static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value;                               \
         560             :                                                                                                                              \
         561             :         static const bool valid = value || !not_const_type;                                                                  \
         562             :       };                                                                                                                     \
         563             :                                                                                                                              \
         564             :       template <class T, class A, bool Valid>                                                                                \
         565             :       struct get_non_member_##test_name##_type { using type = void; };                                                       \
         566             :                                                                                                                              \
         567             :       template <class T, class A>                                                                                            \
         568             :       struct get_non_member_##test_name##_type <T, A, true>                                                                  \
         569             :       {                                                                                                                      \
         570             :         using type = decltype( CEREAL_SAVE_MINIMAL_FUNCTION_NAME( std::declval<A const &>(),                                 \
         571             :                                                                   std::declval<T const &>() versioned ) );                   \
         572             :       };                                                                                                                     \
         573             :     } /* end namespace detail */                                                                                             \
         574             :                                                                                                                              \
         575             :     template <class T, class A>                                                                                              \
         576             :     struct has_non_member_##test_name : std::integral_constant<bool, detail::has_non_member_##test_name##_impl<T, A>::value> \
         577             :     {                                                                                                                        \
         578             :       using check = typename detail::has_non_member_##test_name##_impl<T, A>;                                                \
         579             :       static_assert( check::valid,                                                                                           \
         580             :         "cereal detected a non-const type parameter in non-member " #test_name ". \n "                                       \
         581             :         #test_name " non-member functions must always pass their types as const" );                                          \
         582             :                                                                                                                              \
         583             :       using type = typename detail::get_non_member_##test_name##_type<T, A, check::value>::type;                             \
         584             :       static_assert( (check::value && is_minimal_type<type>::value) || !check::value,                                        \
         585             :         "cereal detected a non-member " #test_name " with an invalid return type. \n "                                       \
         586             :         "return type must be arithmetic or string" );                                                                        \
         587             :     };
         588             :
         589             :     // ######################################################################
         590             :     // Non-Member Save Minimal
         591             :     CEREAL_MAKE_HAS_NON_MEMBER_SAVE_MINIMAL_TEST(save_minimal, )
         592             :
         593             :     // ######################################################################
         594             :     // Non-Member Save Minimal (versioned)
         595             :     CEREAL_MAKE_HAS_NON_MEMBER_SAVE_MINIMAL_TEST(versioned_save_minimal, CEREAL_MAKE_VERSIONED_TEST)
         596             :
         597             :     // ######################################################################
         598             :     #undef CEREAL_MAKE_HAS_NON_MEMBER_SAVE_MINIMAL_TEST
         599             :
         600             :     // ######################################################################
         601             :     // Load Minimal Utilities
         602             :     namespace detail
         603             :     {
         604             :       //! Used to help strip away conversion wrappers
         605             :       /*! If someone writes a non-member load/save minimal function that accepts its
         606             :           parameter as some generic template type and needs to perform trait checks
         607             :           on that type, our NoConvert wrappers will interfere with this.  Using
         608             :           the struct strip_minmal, users can strip away our wrappers to get to
         609             :           the underlying type, allowing traits to work properly */
         610             :       struct NoConvertBase {};
         611             :
         612             :       //! A struct that prevents implicit conversion
         613             :       /*! Any type instantiated with this struct will be unable to implicitly convert
         614             :           to another type.  Is designed to only allow conversion to Source const &.
         615             :
         616             :           @tparam Source the type of the original source */
         617             :       template <class Source>
         618             :       struct NoConvertConstRef : NoConvertBase
         619             :       {
         620             :         using type = Source; //!< Used to get underlying type easily
         621             :
         622             :         template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
         623             :         operator Dest () = delete;
         624             :
         625             :         //! only allow conversion if the types are the same and we are converting into a const reference
         626             :         template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
         627             :         operator Dest const & ();
         628             :       };
         629             :
         630             :       //! A struct that prevents implicit conversion
         631             :       /*! Any type instantiated with this struct will be unable to implicitly convert
         632             :           to another type.  Is designed to only allow conversion to Source &.
         633             :
         634             :           @tparam Source the type of the original source */
         635             :       template <class Source>
         636             :       struct NoConvertRef : NoConvertBase
         637             :       {
         638             :         using type = Source; //!< Used to get underlying type easily
         639             :
         640             :         template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
         641             :         operator Dest () = delete;
         642             :
         643             :         #ifdef __clang__
         644             :         template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
         645             :         operator Dest const & () = delete;
         646             :         #endif // __clang__
         647             :
         648             :         //! only allow conversion if the types are the same and we are converting into a const reference
         649             :         template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
         650             :         operator Dest & ();
         651             :       };
         652             :
         653             :       //! A type that can implicitly convert to anything else
         654             :       struct AnyConvert
         655             :       {
         656             :         template <class Dest>
         657             :         operator Dest & ();
         658             :
         659             :         template <class Dest>
         660             :         operator Dest const & () const;
         661             :       };
         662             :     } // namespace detail
         663             :
         664             :     // ######################################################################
         665             :     //! Creates a test for whether a member load_minimal function exists
         666             :     /*! This creates a class derived from std::integral_constant that will be true if
         667             :         the type has the proper member function for the given archive.
         668             :
         669             :         Our strategy here is to first check if a function matching the signature more or less exists
         670             :         (allow anything like load_minimal(xxx) using AnyConvert, and then secondly enforce
         671             :         that it has the correct signature using NoConvertConstRef
         672             :
         673             :         @param test_name The name to give the test (e.g. load_minimal or versioned_load_minimal)
         674             :         @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
         675             :     #ifdef CEREAL_OLDER_GCC
         676             :     #define CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_IMPL(test_name, versioned)                                                    \
         677             :     namespace detail                                                                                                          \
         678             :     {                                                                                                                         \
         679             :       template <class T, class A, class SFINAE = void> struct has_member_##test_name##_impl : no {};                          \
         680             :       template <class T, class A>                                                                                             \
         681             :       struct has_member_##test_name##_impl<T, A, typename detail::Void< decltype(                                             \
         682             :           cereal::access::member_load_minimal( std::declval<A const &>(),                                                     \
         683             :                                                std::declval<T &>(), AnyConvert() versioned ) ) >::type> : yes {};             \
         684             :                                                                                                                               \
         685             :         template <class T, class A, class U, class SFINAE = void> struct has_member_##test_name##_type_impl : no {};          \
         686             :         template <class T, class A, class U>                                                                                  \
         687             :         struct has_member_##test_name##_type_impl<T, A, U, typename detail::Void< decltype(                                   \
         688             :             cereal::access::member_load_minimal( std::declval<A const &>(),                                                   \
         689             :                                                  std::declval<T &>(), NoConvertConstRef<U>() versioned ) ) >::type> : yes {}; \
         690             :     } /* end namespace detail */
         691             :     #else /* NOT CEREAL_OLDER_GCC =================================== */
         692             :     #define CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_IMPL(test_name, versioned)              \
         693             :     namespace detail                                                                    \
         694             :     {                                                                                   \
         695             :       template <class T, class A>                                                       \
         696             :       struct has_member_##test_name##_impl                                              \
         697             :       {                                                                                 \
         698             :         template <class TT, class AA>                                                   \
         699             :         static auto test(int) -> decltype( cereal::access::member_load_minimal(         \
         700             :               std::declval<AA const &>(),                                               \
         701             :               std::declval<TT &>(), AnyConvert() versioned ), yes());                   \
         702             :         template <class, class> static no test(...);                                    \
         703             :         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;    \
         704             :       };                                                                                \
         705             :       template <class T, class A, class U>                                              \
         706             :       struct has_member_##test_name##_type_impl                                         \
         707             :       {                                                                                 \
         708             :         template <class TT, class AA, class UU>                                         \
         709             :         static auto test(int) -> decltype( cereal::access::member_load_minimal(         \
         710             :               std::declval<AA const &>(),                                               \
         711             :               std::declval<TT &>(), NoConvertConstRef<UU>() versioned ), yes());        \
         712             :         template <class, class, class> static no test(...);                             \
         713             :         static const bool value = std::is_same<decltype(test<T, A, U>(0)), yes>::value; \
         714             :                                                                                         \
         715             :       };                                                                                \
         716             :     } /* end namespace detail */
         717             :     #endif // NOT CEREAL_OLDER_GCC
         718             :
         719             :     // ######################################################################
         720             :     //! Creates helpers for minimal load functions
         721             :     /*! The has_member_*_wrapper structs ensure that the load and save types for the
         722             :         requested function type match appropriately.
         723             :
         724             :         @param load_test_name The name to give the test (e.g. load_minimal or versioned_load_minimal)
         725             :         @param save_test_name The name to give the test (e.g. save_minimal or versioned_save_minimal,
         726             :                               should match the load name.
         727             :         @param save_test_prefix The name to give the test (e.g. save_minimal or versioned_save_minimal,
         728             :                               should match the load name, without the trailing "_minimal" (e.g.
         729             :                               save or versioned_save).  Needed because the preprocessor is an abomination.
         730             :         @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
         731             :     #define CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_HELPERS_IMPL(load_test_name, save_test_name, save_test_prefix, versioned) \
         732             :     namespace detail                                                                                                      \
         733             :     {                                                                                                                     \
         734             :       template <class T, class A, bool Valid>                                                                             \
         735             :       struct has_member_##load_test_name##_wrapper : std::false_type {};                                                  \
         736             :                                                                                                                           \
         737             :       template <class T, class A>                                                                                         \
         738             :       struct has_member_##load_test_name##_wrapper<T, A, true>                                                            \
         739             :       {                                                                                                                   \
         740             :         using AOut = typename detail::get_output_from_input<A>::type;                                                     \
         741             :                                                                                                                           \
         742             :         static_assert( has_member_##save_test_prefix##_minimal<T, AOut>::value,                                           \
         743             :           "cereal detected member " #load_test_name " but no valid member " #save_test_name ". \n "                       \
         744             :           "cannot evaluate correctness of " #load_test_name " without valid " #save_test_name "." );                      \
         745             :                                                                                                                           \
         746             :         using SaveType = typename detail::get_member_##save_test_prefix##_minimal_type<T, AOut, true>::type;              \
         747             :         const static bool value = has_member_##load_test_name##_impl<T, A>::value;                                        \
         748             :         const static bool valid = has_member_##load_test_name##_type_impl<T, A, SaveType>::value;                         \
         749             :                                                                                                                           \
         750             :         static_assert( valid || !value, "cereal detected different or invalid types in corresponding member "             \
         751             :             #load_test_name " and " #save_test_name " functions. \n "                                                     \
         752             :             "the paramater to " #load_test_name " must be a constant reference to the type that "                         \
         753             :             #save_test_name " returns." );                                                                                \
         754             :       };                                                                                                                  \
         755             :     } /* end namespace detail */
         756             :
         757             :     // ######################################################################
         758             :     //! Creates a test for whether a member load_minimal function exists
         759             :     /*! This creates a class derived from std::integral_constant that will be true if
         760             :         the type has the proper member function for the given archive.
         761             :
         762             :         @param load_test_name The name to give the test (e.g. load_minimal or versioned_load_minimal)
         763             :         @param load_test_prefix The above parameter minus the trailing "_minimal" */
         764             :     #define CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_TEST(load_test_name, load_test_prefix)                                         \
         765             :     template <class T, class A>                                                                                                \
         766             :     struct has_member_##load_test_prefix##_minimal : std::integral_constant<bool,                                              \
         767             :       detail::has_member_##load_test_name##_wrapper<T, A, detail::has_member_##load_test_name##_impl<T, A>::value>::value> {};
         768             :
         769             :     // ######################################################################
         770             :     // Member Load Minimal
         771             :     CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_IMPL(load_minimal, )
         772             :     CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_HELPERS_IMPL(load_minimal, save_minimal, save, )
         773             :     CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_TEST(load_minimal, load)
         774             :
         775             :     // ######################################################################
         776             :     // Member Load Minimal (versioned)
         777             :     CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_IMPL(versioned_load_minimal, CEREAL_MAKE_VERSIONED_TEST)
         778             :     CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_HELPERS_IMPL(versioned_load_minimal, versioned_save_minimal, versioned_save, CEREAL_MAKE_VERSIONED_TEST)
         779             :     CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_TEST(versioned_load_minimal, versioned_load)
         780             :
         781             :     // ######################################################################
         782             :     #undef CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_IMPL
         783             :     #undef CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_HELPERS_IMPL
         784             :     #undef CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_TEST
         785             :
         786             :     // ######################################################################
         787             :     // Non-Member Load Minimal
         788             :     namespace detail
         789             :     {
         790             :       #ifdef CEREAL_OLDER_GCC
         791             :       void CEREAL_LOAD_MINIMAL_FUNCTION_NAME(); // prevents nonsense complaining about not finding this
         792             :       void CEREAL_SAVE_MINIMAL_FUNCTION_NAME();
         793             :       #endif // CEREAL_OLDER_GCC
         794             :     } // namespace detail
         795             :
         796             :     // ######################################################################
         797             :     //! Creates a test for whether a non-member load_minimal function exists
         798             :     /*! This creates a class derived from std::integral_constant that will be true if
         799             :         the type has the proper member function for the given archive.
         800             :
         801             :         See notes from member load_minimal implementation.
         802             :
         803             :         Note that there should be an additional const check on load_minimal after the valid check,
         804             :         but this currently interferes with many valid uses of minimal serialization.  It has been
         805             :         removed (see #565 on github) and previously was:
         806             :
         807             :         @code
         808             :         static_assert( check::const_valid || !check::exists,
         809             :             "cereal detected an invalid serialization type parameter in non-member " #test_name ".  "
         810             :             #test_name " non-member functions must accept their serialization type by non-const reference" );
         811             :         @endcode
         812             :
         813             :         See #132, #436, #263, and #565 on https://github.com/USCiLab/cereal for more details.
         814             :
         815             :         @param test_name The name to give the test (e.g. load_minimal or versioned_load_minimal)
         816             :         @param save_name The corresponding name the save test would have (e.g. save_minimal or versioned_save_minimal)
         817             :         @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
         818             :     #define CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST(test_name, save_name, versioned)                                    \
         819             :     namespace detail                                                                                                         \
         820             :     {                                                                                                                        \
         821             :       template <class T, class A, class U = void>                                                                            \
         822             :       struct has_non_member_##test_name##_impl                                                                               \
         823             :       {                                                                                                                      \
         824             :         template <class TT, class AA>                                                                                        \
         825             :         static auto test(int) -> decltype( CEREAL_LOAD_MINIMAL_FUNCTION_NAME(                                                \
         826             :               std::declval<AA const &>(), std::declval<TT&>(), AnyConvert() versioned ), yes() );                            \
         827             :         template <class, class> static no test( ... );                                                                       \
         828             :         static const bool exists = std::is_same<decltype( test<T, A>( 0 ) ), yes>::value;                                    \
         829             :                                                                                                                              \
         830             :         template <class TT, class AA, class UU>                                                                              \
         831             :         static auto test2(int) -> decltype( CEREAL_LOAD_MINIMAL_FUNCTION_NAME(                                               \
         832             :               std::declval<AA const &>(), std::declval<TT&>(), NoConvertConstRef<UU>() versioned ), yes() );                 \
         833             :         template <class, class, class> static no test2( ... );                                                               \
         834             :         static const bool valid = std::is_same<decltype( test2<T, A, U>( 0 ) ), yes>::value;                                 \
         835             :                                                                                                                              \
         836             :         template <class TT, class AA>                                                                                        \
         837             :         static auto test3(int) -> decltype( CEREAL_LOAD_MINIMAL_FUNCTION_NAME(                                               \
         838             :               std::declval<AA const &>(), NoConvertRef<TT>(), AnyConvert() versioned ), yes() );                             \
         839             :         template <class, class> static no test3( ... );                                                                      \
         840             :         static const bool const_valid = std::is_same<decltype( test3<T, A>( 0 ) ), yes>::value;                              \
         841             :       };                                                                                                                     \
         842             :                                                                                                                              \
         843             :       template <class T, class A, bool Valid>                                                                                \
         844             :       struct has_non_member_##test_name##_wrapper : std::false_type {};                                                      \
         845             :                                                                                                                              \
         846             :       template <class T, class A>                                                                                            \
         847             :       struct has_non_member_##test_name##_wrapper<T, A, true>                                                                \
         848             :       {                                                                                                                      \
         849             :         using AOut = typename detail::get_output_from_input<A>::type;                                                        \
         850             :                                                                                                                              \
         851             :         static_assert( detail::has_non_member_##save_name##_impl<T, AOut>::valid,                                            \
         852             :           "cereal detected non-member " #test_name " but no valid non-member " #save_name ". \n "                            \
         853             :           "cannot evaluate correctness of " #test_name " without valid " #save_name "." );                                   \
         854             :                                                                                                                              \
         855             :         using SaveType = typename detail::get_non_member_##save_name##_type<T, AOut, true>::type;                            \
         856             :         using check = has_non_member_##test_name##_impl<T, A, SaveType>;                                                     \
         857             :         static const bool value = check::exists;                                                                             \
         858             :                                                                                                                              \
         859             :         static_assert( check::valid || !check::exists, "cereal detected different types in corresponding non-member "        \
         860             :             #test_name " and " #save_name " functions. \n "                                                                  \
         861             :             "the paramater to " #test_name " must be a constant reference to the type that " #save_name " returns." );       \
         862             :       };                                                                                                                     \
         863             :     } /* namespace detail */                                                                                                 \
         864             :                                                                                                                              \
         865             :     template <class T, class A>                                                                                              \
         866             :     struct has_non_member_##test_name : std::integral_constant<bool,                                                         \
         867             :       detail::has_non_member_##test_name##_wrapper<T, A, detail::has_non_member_##test_name##_impl<T, A>::exists>::value> {};
         868             :
         869             :     // ######################################################################
         870             :     // Non-Member Load Minimal
         871             :     CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST(load_minimal, save_minimal, )
         872             :
         873             :     // ######################################################################
         874             :     // Non-Member Load Minimal (versioned)
         875             :     CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST(versioned_load_minimal, versioned_save_minimal, CEREAL_MAKE_VERSIONED_TEST)
         876             :
         877             :     // ######################################################################
         878             :     #undef CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST
         879             :
         880             :     // ######################################################################
         881             :     namespace detail
         882             :     {
         883             :       // const stripped away before reaching here, prevents errors on conversion from
         884             :       // construct<const T> to construct<T>
         885             :       template<typename T, typename A>
         886             :       struct has_member_load_and_construct_impl : std::integral_constant<bool,
         887             :         std::is_same<decltype( access::load_and_construct<T>( std::declval<A&>(), std::declval< ::cereal::construct<T>&>() ) ), void>::value>
         888             :       { };
         889             :
         890             :       template<typename T, typename A>
         891             :       struct has_member_versioned_load_and_construct_impl : std::integral_constant<bool,
         892             :         std::is_same<decltype( access::load_and_construct<T>( std::declval<A&>(), std::declval< ::cereal::construct<T>&>(), 0 ) ), void>::value>
         893             :       { };
         894             :     } // namespace detail
         895             :
         896             :     //! Member load and construct check
         897             :     template<typename T, typename A>
         898             :     struct has_member_load_and_construct : detail::has_member_load_and_construct_impl<typename std::remove_const<T>::type, A>
         899             :     { };
         900             :
         901             :     //! Member load and construct check (versioned)
         902             :     template<typename T, typename A>
         903             :     struct has_member_versioned_load_and_construct : detail::has_member_versioned_load_and_construct_impl<typename std::remove_const<T>::type, A>
         904             :     { };
         905             :
         906             :     // ######################################################################
         907             :     //! Creates a test for whether a non-member load_and_construct specialization exists
         908             :     /*! This creates a class derived from std::integral_constant that will be true if
         909             :         the type has the proper non-member function for the given archive. */
         910             :     #define CEREAL_MAKE_HAS_NON_MEMBER_LOAD_AND_CONSTRUCT_TEST(test_name, versioned)                                            \
         911             :     namespace detail                                                                                                            \
         912             :     {                                                                                                                           \
         913             :       template <class T, class A>                                                                                               \
         914             :       struct has_non_member_##test_name##_impl                                                                                  \
         915             :       {                                                                                                                         \
         916             :         template <class TT, class AA>                                                                                           \
         917             :         static auto test(int) -> decltype( LoadAndConstruct<TT>::load_and_construct(                                            \
         918             :                                            std::declval<AA&>(), std::declval< ::cereal::construct<TT>&>() versioned ), yes());  \
         919             :         template <class, class>                                                                                                 \
         920             :         static no test( ... );                                                                                                  \
         921             :         static const bool value = std::is_same<decltype( test<T, A>( 0 ) ), yes>::value;                                        \
         922             :       };                                                                                                                        \
         923             :     } /* end namespace detail */                                                                                                \
         924             :     template <class T, class A>                                                                                                 \
         925             :     struct has_non_member_##test_name :                                                                                         \
         926             :       std::integral_constant<bool, detail::has_non_member_##test_name##_impl<typename std::remove_const<T>::type, A>::value> {};
         927             :
         928             :     // ######################################################################
         929             :     //! Non member load and construct check
         930             :     CEREAL_MAKE_HAS_NON_MEMBER_LOAD_AND_CONSTRUCT_TEST(load_and_construct, )
         931             :
         932             :     // ######################################################################
         933             :     //! Non member load and construct check (versioned)
         934             :     CEREAL_MAKE_HAS_NON_MEMBER_LOAD_AND_CONSTRUCT_TEST(versioned_load_and_construct, CEREAL_MAKE_VERSIONED_TEST)
         935             :
         936             :     // ######################################################################
         937             :     //! Has either a member or non member load and construct
         938             :     template<typename T, typename A>
         939             :     struct has_load_and_construct : std::integral_constant<bool,
         940             :       has_member_load_and_construct<T, A>::value || has_non_member_load_and_construct<T, A>::value ||
         941             :       has_member_versioned_load_and_construct<T, A>::value || has_non_member_versioned_load_and_construct<T, A>::value>
         942             :     { };
         943             :
         944             :     // ######################################################################
         945             :     #undef CEREAL_MAKE_HAS_NON_MEMBER_LOAD_AND_CONSTRUCT_TEST
         946             :
         947             :     // ######################################################################
         948             :     // End of serialization existence tests
         949             :     #undef CEREAL_MAKE_VERSIONED_TEST
         950             :
         951             :     // ######################################################################
         952             :     template <class T, class InputArchive, class OutputArchive>
         953             :     struct has_member_split : std::integral_constant<bool,
         954             :       (has_member_load<T, InputArchive>::value && has_member_save<T, OutputArchive>::value) ||
         955             :       (has_member_versioned_load<T, InputArchive>::value && has_member_versioned_save<T, OutputArchive>::value)> {};
         956             :
         957             :     // ######################################################################
         958             :     template <class T, class InputArchive, class OutputArchive>
         959             :     struct has_non_member_split : std::integral_constant<bool,
         960             :       (has_non_member_load<T, InputArchive>::value && has_non_member_save<T, OutputArchive>::value) ||
         961             :       (has_non_member_versioned_load<T, InputArchive>::value && has_non_member_versioned_save<T, OutputArchive>::value)> {};
         962             :
         963             :     // ######################################################################
         964             :     template <class T, class OutputArchive>
         965             :     struct has_invalid_output_versioning : std::integral_constant<bool,
         966             :       (has_member_versioned_save<T, OutputArchive>::value && has_member_save<T, OutputArchive>::value) ||
         967             :       (has_non_member_versioned_save<T, OutputArchive>::value && has_non_member_save<T, OutputArchive>::value) ||
         968             :       (has_member_versioned_serialize<T, OutputArchive>::value && has_member_serialize<T, OutputArchive>::value) ||
         969             :       (has_non_member_versioned_serialize<T, OutputArchive>::value && has_non_member_serialize<T, OutputArchive>::value) ||
         970             :       (has_member_versioned_save_minimal<T, OutputArchive>::value && has_member_save_minimal<T, OutputArchive>::value) ||
         971             :       (has_non_member_versioned_save_minimal<T, OutputArchive>::value &&  has_non_member_save_minimal<T, OutputArchive>::value)> {};
         972             :
         973             :     // ######################################################################
         974             :     template <class T, class InputArchive>
         975             :     struct has_invalid_input_versioning : std::integral_constant<bool,
         976             :       (has_member_versioned_load<T, InputArchive>::value && has_member_load<T, InputArchive>::value) ||
         977             :       (has_non_member_versioned_load<T, InputArchive>::value && has_non_member_load<T, InputArchive>::value) ||
         978             :       (has_member_versioned_serialize<T, InputArchive>::value && has_member_serialize<T, InputArchive>::value) ||
         979             :       (has_non_member_versioned_serialize<T, InputArchive>::value && has_non_member_serialize<T, InputArchive>::value) ||
         980             :       (has_member_versioned_load_minimal<T, InputArchive>::value && has_member_load_minimal<T, InputArchive>::value) ||
         981             :       (has_non_member_versioned_load_minimal<T, InputArchive>::value &&  has_non_member_load_minimal<T, InputArchive>::value)> {};
         982             :
         983             :     // ######################################################################
         984             :     namespace detail
         985             :     {
         986             :       //! Create a test for a cereal::specialization entry
         987             :       #define CEREAL_MAKE_IS_SPECIALIZED_IMPL(name)                                          \
         988             :       template <class T, class A>                                                            \
         989             :       struct is_specialized_##name : std::integral_constant<bool,                            \
         990             :         !std::is_base_of<std::false_type, specialize<A, T, specialization::name>>::value> {}
         991             :
         992             :       CEREAL_MAKE_IS_SPECIALIZED_IMPL(member_serialize);
         993             :       CEREAL_MAKE_IS_SPECIALIZED_IMPL(member_load_save);
         994             :       CEREAL_MAKE_IS_SPECIALIZED_IMPL(member_load_save_minimal);
         995             :       CEREAL_MAKE_IS_SPECIALIZED_IMPL(non_member_serialize);
         996             :       CEREAL_MAKE_IS_SPECIALIZED_IMPL(non_member_load_save);
         997             :       CEREAL_MAKE_IS_SPECIALIZED_IMPL(non_member_load_save_minimal);
         998             :
         999             :       #undef CEREAL_MAKE_IS_SPECIALIZED_IMPL
        1000             :
        1001             :       //! Number of specializations detected
        1002             :       template <class T, class A>
        1003             :       struct count_specializations : std::integral_constant<int,
        1004             :         is_specialized_member_serialize<T, A>::value +
        1005             :         is_specialized_member_load_save<T, A>::value +
        1006             :         is_specialized_member_load_save_minimal<T, A>::value +
        1007             :         is_specialized_non_member_serialize<T, A>::value +
        1008             :         is_specialized_non_member_load_save<T, A>::value +
        1009             :         is_specialized_non_member_load_save_minimal<T, A>::value> {};
        1010             :     } // namespace detail
        1011             :
        1012             :     //! Check if any specialization exists for a type
        1013             :     template <class T, class A>
        1014             :     struct is_specialized : std::integral_constant<bool,
        1015             :       detail::is_specialized_member_serialize<T, A>::value ||
        1016             :       detail::is_specialized_member_load_save<T, A>::value ||
        1017             :       detail::is_specialized_member_load_save_minimal<T, A>::value ||
        1018             :       detail::is_specialized_non_member_serialize<T, A>::value ||
        1019             :       detail::is_specialized_non_member_load_save<T, A>::value ||
        1020             :       detail::is_specialized_non_member_load_save_minimal<T, A>::value>
        1021             :     {
        1022             :       static_assert(detail::count_specializations<T, A>::value <= 1, "More than one explicit specialization detected for type.");
        1023             :     };
        1024             :
        1025             :     //! Create the static assertion for some specialization
        1026             :     /*! This assertion will fail if the type is indeed specialized and does not have the appropriate
        1027             :         type of serialization functions */
        1028             :     #define CEREAL_MAKE_IS_SPECIALIZED_ASSERT(name, versioned_name, print_name, spec_name)                      \
        1029             :     static_assert( (is_specialized<T, A>::value && detail::is_specialized_##spec_name<T, A>::value &&           \
        1030             :                    (has_##name<T, A>::value || has_##versioned_name<T, A>::value))                              \
        1031             :                    || !(is_specialized<T, A>::value && detail::is_specialized_##spec_name<T, A>::value),        \
        1032             :                    "cereal detected " #print_name " specialization but no " #print_name " serialize function" )
        1033             :
        1034             :     //! Generates a test for specialization for versioned and unversioned functions
        1035             :     /*! This creates checks that can be queried to see if a given type of serialization function
        1036             :         has been specialized for this type */
        1037             :     #define CEREAL_MAKE_IS_SPECIALIZED(name, versioned_name, spec_name)                     \
        1038             :     template <class T, class A>                                                             \
        1039             :     struct is_specialized_##name : std::integral_constant<bool,                             \
        1040             :       is_specialized<T, A>::value && detail::is_specialized_##spec_name<T, A>::value>       \
        1041             :     { CEREAL_MAKE_IS_SPECIALIZED_ASSERT(name, versioned_name, name, spec_name); };          \
        1042             :     template <class T, class A>                                                             \
        1043             :     struct is_specialized_##versioned_name : std::integral_constant<bool,                   \
        1044             :       is_specialized<T, A>::value && detail::is_specialized_##spec_name<T, A>::value>       \
        1045             :     { CEREAL_MAKE_IS_SPECIALIZED_ASSERT(name, versioned_name, versioned_name, spec_name); }
        1046             :
        1047             :     CEREAL_MAKE_IS_SPECIALIZED(member_serialize, member_versioned_serialize, member_serialize);
        1048             :     CEREAL_MAKE_IS_SPECIALIZED(non_member_serialize, non_member_versioned_serialize, non_member_serialize);
        1049             :
        1050             :     CEREAL_MAKE_IS_SPECIALIZED(member_save, member_versioned_save, member_load_save);
        1051             :     CEREAL_MAKE_IS_SPECIALIZED(non_member_save, non_member_versioned_save, non_member_load_save);
        1052             :     CEREAL_MAKE_IS_SPECIALIZED(member_load, member_versioned_load, member_load_save);
        1053             :     CEREAL_MAKE_IS_SPECIALIZED(non_member_load, non_member_versioned_load, non_member_load_save);
        1054             :
        1055             :     CEREAL_MAKE_IS_SPECIALIZED(member_save_minimal, member_versioned_save_minimal, member_load_save_minimal);
        1056             :     CEREAL_MAKE_IS_SPECIALIZED(non_member_save_minimal, non_member_versioned_save_minimal, non_member_load_save_minimal);
        1057             :     CEREAL_MAKE_IS_SPECIALIZED(member_load_minimal, member_versioned_load_minimal, member_load_save_minimal);
        1058             :     CEREAL_MAKE_IS_SPECIALIZED(non_member_load_minimal, non_member_versioned_load_minimal, non_member_load_save_minimal);
        1059             :
        1060             :     #undef CEREAL_MAKE_IS_SPECIALIZED_ASSERT
        1061             :     #undef CEREAL_MAKE_IS_SPECIALIZED
        1062             :
        1063             :     // ######################################################################
        1064             :     // detects if a type has any active minimal output serialization
        1065             :     template <class T, class OutputArchive>
        1066             :     struct has_minimal_output_serialization : std::integral_constant<bool,
        1067             :       is_specialized_member_save_minimal<T, OutputArchive>::value ||
        1068             :       ((has_member_save_minimal<T, OutputArchive>::value ||
        1069             :         has_non_member_save_minimal<T, OutputArchive>::value ||
        1070             :         has_member_versioned_save_minimal<T, OutputArchive>::value ||
        1071             :         has_non_member_versioned_save_minimal<T, OutputArchive>::value) &&
        1072             :        !(is_specialized_member_serialize<T, OutputArchive>::value ||
        1073             :          is_specialized_member_save<T, OutputArchive>::value))> {};
        1074             :
        1075             :     // ######################################################################
        1076             :     // detects if a type has any active minimal input serialization
        1077             :     template <class T, class InputArchive>
        1078             :     struct has_minimal_input_serialization : std::integral_constant<bool,
        1079             :       is_specialized_member_load_minimal<T, InputArchive>::value ||
        1080             :       ((has_member_load_minimal<T, InputArchive>::value ||
        1081             :         has_non_member_load_minimal<T, InputArchive>::value ||
        1082             :         has_member_versioned_load_minimal<T, InputArchive>::value ||
        1083             :         has_non_member_versioned_load_minimal<T, InputArchive>::value) &&
        1084             :        !(is_specialized_member_serialize<T, InputArchive>::value ||
        1085             :          is_specialized_member_load<T, InputArchive>::value))> {};
        1086             :
        1087             :     // ######################################################################
        1088             :     namespace detail
        1089             :     {
        1090             :       //! The number of output serialization functions available
        1091             :       /*! If specialization is being used, we'll count only those; otherwise we'll count everything */
        1092             :       template <class T, class OutputArchive>
        1093             :       struct count_output_serializers : std::integral_constant<int,
        1094             :         count_specializations<T, OutputArchive>::value ? count_specializations<T, OutputArchive>::value :
        1095             :         has_member_save<T, OutputArchive>::value +
        1096             :         has_non_member_save<T, OutputArchive>::value +
        1097             :         has_member_serialize<T, OutputArchive>::value +
        1098             :         has_non_member_serialize<T, OutputArchive>::value +
        1099             :         has_member_save_minimal<T, OutputArchive>::value +
        1100             :         has_non_member_save_minimal<T, OutputArchive>::value +
        1101             :         /*-versioned---------------------------------------------------------*/
        1102             :         has_member_versioned_save<T, OutputArchive>::value +
        1103             :         has_non_member_versioned_save<T, OutputArchive>::value +
        1104             :         has_member_versioned_serialize<T, OutputArchive>::value +
        1105             :         has_non_member_versioned_serialize<T, OutputArchive>::value +
        1106             :         has_member_versioned_save_minimal<T, OutputArchive>::value +
        1107             :         has_non_member_versioned_save_minimal<T, OutputArchive>::value> {};
        1108             :     }
        1109             :
        1110             :     template <class T, class OutputArchive>
        1111             :     struct is_output_serializable : std::integral_constant<bool,
        1112             :       detail::count_output_serializers<T, OutputArchive>::value == 1> {};
        1113             :
        1114             :     // ######################################################################
        1115             :     namespace detail
        1116             :     {
        1117             :       //! The number of input serialization functions available
        1118             :       /*! If specialization is being used, we'll count only those; otherwise we'll count everything */
        1119             :       template <class T, class InputArchive>
        1120             :       struct count_input_serializers : std::integral_constant<int,
        1121             :         count_specializations<T, InputArchive>::value ? count_specializations<T, InputArchive>::value :
        1122             :         has_member_load<T, InputArchive>::value +
        1123             :         has_non_member_load<T, InputArchive>::value +
        1124             :         has_member_serialize<T, InputArchive>::value +
        1125             :         has_non_member_serialize<T, InputArchive>::value +
        1126             :         has_member_load_minimal<T, InputArchive>::value +
        1127             :         has_non_member_load_minimal<T, InputArchive>::value +
        1128             :         /*-versioned---------------------------------------------------------*/
        1129             :         has_member_versioned_load<T, InputArchive>::value +
        1130             :         has_non_member_versioned_load<T, InputArchive>::value +
        1131             :         has_member_versioned_serialize<T, InputArchive>::value +
        1132             :         has_non_member_versioned_serialize<T, InputArchive>::value +
        1133             :         has_member_versioned_load_minimal<T, InputArchive>::value +
        1134             :         has_non_member_versioned_load_minimal<T, InputArchive>::value> {};
        1135             :     }
        1136             :
        1137             :     template <class T, class InputArchive>
        1138             :     struct is_input_serializable : std::integral_constant<bool,
        1139             :       detail::count_input_serializers<T, InputArchive>::value == 1> {};
        1140             :
        1141             :     // ######################################################################
        1142             :     // Base Class Support
        1143             :     namespace detail
        1144             :     {
        1145             :       struct base_class_id
        1146             :       {
        1147             :         template<class T>
        1148        3200 :           base_class_id(T const * const t) :
        1149             :           type(typeid(T)),
        1150             :           ptr(t),
        1151        3200 :           hash(std::hash<std::type_index>()(typeid(T)) ^ (std::hash<void const *>()(t) << 1))
        1152        3200 :           { }
        1153             :
        1154        1600 :           bool operator==(base_class_id const & other) const
        1155        1600 :           { return (type == other.type) && (ptr == other.ptr); }
        1156             :
        1157             :           std::type_index type;
        1158             :           void const * ptr;
        1159             :           size_t hash;
        1160             :       };
        1161        4800 :       struct base_class_id_hash { size_t operator()(base_class_id const & id) const { return id.hash; }  };
        1162             :     } // namespace detail
        1163             :
        1164             :     namespace detail
        1165             :     {
        1166             :       //! Common base type for base class casting
        1167             :       struct BaseCastBase {};
        1168             :
        1169             :       template <class>
        1170             :       struct get_base_class;
        1171             :
        1172             :       template <template<typename> class Cast, class Base>
        1173             :       struct get_base_class<Cast<Base>>
        1174             :       {
        1175             :         using type = Base;
        1176             :       };
        1177             :
        1178             :       //! Base class cast, behave as the test
        1179             :       template <class Cast, template<class, class> class Test, class Archive,
        1180             :                 bool IsBaseCast = std::is_base_of<BaseCastBase, Cast>::value>
        1181             :       struct has_minimal_base_class_serialization_impl : Test<typename get_base_class<Cast>::type, Archive>
        1182             :       { };
        1183             :
        1184             :       //! Not a base class cast
        1185             :       template <class Cast, template<class, class> class Test, class Archive>
        1186             :       struct has_minimal_base_class_serialization_impl<Cast,Test, Archive, false> : std::false_type
        1187             :       { };
        1188             :     }
        1189             :
        1190             :     //! Checks to see if the base class used in a cast has a minimal serialization
        1191             :     /*! @tparam Cast Either base_class or virtual_base_class wrapped type
        1192             :         @tparam Test A has_minimal test (for either input or output)
        1193             :         @tparam Archive The archive to use with the test */
        1194             :     template <class Cast, template<class, class> class Test, class Archive>
        1195             :     struct has_minimal_base_class_serialization : detail::has_minimal_base_class_serialization_impl<Cast, Test, Archive>
        1196             :     { };
        1197             :
        1198             :
        1199             :     // ######################################################################
        1200             :     namespace detail
        1201             :     {
        1202             :       struct shared_from_this_wrapper
        1203             :       {
        1204             :         template <class U>
        1205             :         static auto (check)( U const & t ) -> decltype( ::cereal::access::shared_from_this(t), std::true_type() );
        1206             :
        1207             :         static auto (check)( ... ) -> decltype( std::false_type() );
        1208             :
        1209             :         template <class U>
        1210             :         static auto get( U const & t ) -> decltype( t.shared_from_this() );
        1211             :       };
        1212             :     }
        1213             :
        1214             :     //! Determine if T or any base class of T has inherited from std::enable_shared_from_this
        1215             :     template<class T>
        1216             :     struct has_shared_from_this : decltype((detail::shared_from_this_wrapper::check)(std::declval<T>()))
        1217             :     { };
        1218             :
        1219             :     //! Get the type of the base class of T which inherited from std::enable_shared_from_this
        1220             :     template <class T>
        1221             :     struct get_shared_from_this_base
        1222             :     {
        1223             :       private:
        1224             :         using PtrType = decltype(detail::shared_from_this_wrapper::get(std::declval<T>()));
        1225             :       public:
        1226             :         //! The type of the base of T that inherited from std::enable_shared_from_this
        1227             :         using type = typename std::decay<typename PtrType::element_type>::type;
        1228             :     };
        1229             :
        1230             :     // ######################################################################
        1231             :     //! Extracts the true type from something possibly wrapped in a cereal NoConvert
        1232             :     /*! Internally cereal uses some wrapper classes to test the validity of non-member
        1233             :         minimal load and save functions.  This can interfere with user type traits on
        1234             :         templated load and save minimal functions.  To get to the correct underlying type,
        1235             :         users should use strip_minimal when performing any enable_if type type trait checks.
        1236             :
        1237             :         See the enum serialization in types/common.hpp for an example of using this */
        1238             :     template <class T, bool IsCerealMinimalTrait = std::is_base_of<detail::NoConvertBase, T>::value>
        1239             :     struct strip_minimal
        1240             :     {
        1241             :       using type = T;
        1242             :     };
        1243             :
        1244             :     //! Specialization for types wrapped in a NoConvert
        1245             :     template <class T>
        1246             :     struct strip_minimal<T, true>
        1247             :     {
        1248             :       using type = typename T::type;
        1249             :     };
        1250             :
        1251             :     // ######################################################################
        1252             :     //! Determines whether the class T can be default constructed by cereal::access
        1253             :     template <class T>
        1254             :     struct is_default_constructible
        1255             :     {
        1256             :       #ifdef CEREAL_OLDER_GCC
        1257             :       template <class TT, class SFINAE = void>
        1258             :       struct test : no {};
        1259             :       template <class TT>
        1260             :       struct test<TT, typename detail::Void< decltype( cereal::access::construct<TT>() ) >::type> : yes {};
        1261             :       static const bool value = test<T>();
        1262             :       #else // NOT CEREAL_OLDER_GCC =========================================
        1263             :       template <class TT>
        1264             :       static auto test(int) -> decltype( cereal::access::construct<TT>(), yes());
        1265             :       template <class>
        1266             :       static no test(...);
        1267             :       static const bool value = std::is_same<decltype(test<T>(0)), yes>::value;
        1268             :       #endif // NOT CEREAL_OLDER_GCC
        1269             :     };
        1270             :
        1271             :     // ######################################################################
        1272             :     namespace detail
        1273             :     {
        1274             :       //! Removes all qualifiers and minimal wrappers from an archive
        1275             :       template <class A>
        1276             :       using decay_archive = typename std::decay<typename strip_minimal<A>::type>::type;
        1277             :     }
        1278             :
        1279             :     //! Checks if the provided archive type is equal to some cereal archive type
        1280             :     /*! This automatically does things such as std::decay and removing any other wrappers that may be
        1281             :         on the Archive template parameter.
        1282             :
        1283             :         Example use:
        1284             :         @code{cpp}
        1285             :         // example use to disable a serialization function
        1286             :         template <class Archive, EnableIf<cereal::traits::is_same_archive<Archive, cereal::BinaryOutputArchive>::value> = sfinae>
        1287             :         void save( Archive & ar, MyType const & mt );
        1288             :         @endcode */
        1289             :     template <class ArchiveT, class CerealArchiveT>
        1290             :     struct is_same_archive : std::integral_constant<bool,
        1291             :       std::is_same<detail::decay_archive<ArchiveT>, CerealArchiveT>::value>
        1292             :     { };
        1293             :
        1294             :     // ######################################################################
        1295             :     //! A macro to use to restrict which types of archives your function will work for.
        1296             :     /*! This requires you to have a template class parameter named Archive and replaces the void return
        1297             :         type for your function.
        1298             :
        1299             :         INTYPE refers to the input archive type you wish to restrict on.
        1300             :         OUTTYPE refers to the output archive type you wish to restrict on.
        1301             :
        1302             :         For example, if we want to limit a serialize to only work with binary serialization:
        1303             :
        1304             :         @code{.cpp}
        1305             :         template <class Archive>
        1306             :         CEREAL_ARCHIVE_RESTRICT(BinaryInputArchive, BinaryOutputArchive)
        1307             :         serialize( Archive & ar, MyCoolType & m )
        1308             :         {
        1309             :           ar & m;
        1310             :         }
        1311             :         @endcode
        1312             :
        1313             :         If you need to do more restrictions in your enable_if, you will need to do this by hand.
        1314             :      */
        1315             :     #define CEREAL_ARCHIVE_RESTRICT(INTYPE, OUTTYPE) \
        1316             :     typename std::enable_if<cereal::traits::is_same_archive<Archive, INTYPE>::value || cereal::traits::is_same_archive<Archive, OUTTYPE>::value, void>::type
        1317             :
        1318             :     //! Type traits only struct used to mark an archive as human readable (text based)
        1319             :     /*! Archives that wish to identify as text based/human readable should inherit from
        1320             :         this struct */
        1321             :     struct TextArchive {};
        1322             :
        1323             :     //! Checks if an archive is a text archive (human readable)
        1324             :     template <class A>
        1325             :     struct is_text_archive : std::integral_constant<bool,
        1326             :       std::is_base_of<TextArchive, detail::decay_archive<A>>::value>
        1327             :     { };
        1328             :   } // namespace traits
        1329             :
        1330             :   // ######################################################################
        1331             :   namespace detail
        1332             :   {
        1333             :     template <class T, class A,
        1334             :               bool Member = traits::has_member_load_and_construct<T, A>::value,
        1335             :               bool MemberVersioned = traits::has_member_versioned_load_and_construct<T, A>::value,
        1336             :               bool NonMember = traits::has_non_member_load_and_construct<T, A>::value,
        1337             :               bool NonMemberVersioned = traits::has_non_member_versioned_load_and_construct<T, A>::value>
        1338             :     struct Construct
        1339             :     {
        1340             :       static_assert( cereal::traits::detail::delay_static_assert<T>::value,
        1341             :         "cereal found more than one compatible load_and_construct function for the provided type and archive combination. \n\n "
        1342             :         "Types must either have a member load_and_construct function or a non-member specialization of LoadAndConstruct (you may not mix these). \n "
        1343             :         "In addition, you may not mix versioned with non-versioned load_and_construct functions. \n\n " );
        1344             :       static T * load_andor_construct( A & /*ar*/, construct<T> & /*construct*/ )
        1345             :       { return nullptr; }
        1346             :     };
        1347             :
        1348             :     // no load and construct case
        1349             :     template <class T, class A>
        1350             :     struct Construct<T, A, false, false, false, false>
        1351             :     {
        1352             :       static_assert( ::cereal::traits::is_default_constructible<T>::value,
        1353             :                      "Trying to serialize a an object with no default constructor. \n\n "
        1354             :                      "Types must either be default constructible or define either a member or non member Construct function. \n "
        1355             :                      "Construct functions generally have the signature: \n\n "
        1356             :                      "template <class Archive> \n "
        1357             :                      "static void load_and_construct(Archive & ar, cereal::construct<T> & construct) \n "
        1358             :                      "{ \n "
        1359             :                      "  var a; \n "
        1360             :                      "  ar( a ) \n "
        1361             :                      "  construct( a ); \n "
        1362             :                      "} \n\n" );
        1363       85608 :       static T * load_andor_construct()
        1364       85608 :       { return ::cereal::access::construct<T>(); }
        1365             :     };
        1366             :
        1367             :     // member non-versioned
        1368             :     template <class T, class A>
        1369             :     struct Construct<T, A, true, false, false, false>
        1370             :     {
        1371        5200 :       static void load_andor_construct( A & ar, construct<T> & construct )
        1372             :       {
        1373        5200 :         access::load_and_construct<T>( ar, construct );
        1374        4800 :       }
        1375             :     };
        1376             :
        1377             :     // member versioned
        1378             :     template <class T, class A>
        1379             :     struct Construct<T, A, false, true, false, false>
        1380             :     {
        1381         800 :       static void load_andor_construct( A & ar, construct<T> & construct )
        1382             :       {
        1383         800 :         const auto version = ar.template loadClassVersion<T>();
        1384         800 :         access::load_and_construct<T>( ar, construct, version );
        1385         800 :       }
        1386             :     };
        1387             :
        1388             :     // non-member non-versioned
        1389             :     template <class T, class A>
        1390             :     struct Construct<T, A, false, false, true, false>
        1391             :     {
        1392        1604 :       static void load_andor_construct( A & ar, construct<T> & construct )
        1393             :       {
        1394        1604 :         LoadAndConstruct<T>::load_and_construct( ar, construct );
        1395        1604 :       }
        1396             :     };
        1397             :
        1398             :     // non-member versioned
        1399             :     template <class T, class A>
        1400             :     struct Construct<T, A, false, false, false, true>
        1401             :     {
        1402         800 :       static void load_andor_construct( A & ar, construct<T> & construct )
        1403             :       {
        1404         800 :         const auto version = ar.template loadClassVersion<T>();
        1405         800 :         LoadAndConstruct<T>::load_and_construct( ar, construct, version );
        1406         800 :       }
        1407             :     };
        1408             :   } // namespace detail
        1409             : } // namespace cereal
        1410             :
        1411             : #endif // CEREAL_DETAILS_TRAITS_HPP_

Generated by: LCOV version 1.14