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