LCOV - code coverage report
Current view: top level - cereal/details - traits.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 24 24 100.0 %
Date: 2017-02-12 13:57:59 Functions: 62 66 93.9 %

          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 cereal 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 RANDOLPH VOORHIES OR SHANE GRANT 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             :         @param test_name The name to give the test (e.g. load_minimal or versioned_load_minimal)
     804             :         @param save_name The corresponding name the save test would have (e.g. save_minimal or versioned_save_minimal)
     805             :         @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
     806             :     #define CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST(test_name, save_name, versioned)                                    \
     807             :     namespace detail                                                                                                         \
     808             :     {                                                                                                                        \
     809             :       template <class T, class A, class U = void>                                                                            \
     810             :       struct has_non_member_##test_name##_impl                                                                               \
     811             :       {                                                                                                                      \
     812             :         template <class TT, class AA>                                                                                        \
     813             :         static auto test(int) -> decltype( CEREAL_LOAD_MINIMAL_FUNCTION_NAME(                                                \
     814             :               std::declval<AA const &>(), std::declval<TT&>(), AnyConvert() versioned ), yes() );                            \
     815             :         template <class, class> static no test( ... );                                                                       \
     816             :         static const bool exists = std::is_same<decltype( test<T, A>( 0 ) ), yes>::value;                                    \
     817             :                                                                                                                              \
     818             :         template <class TT, class AA, class UU>                                                                              \
     819             :         static auto test2(int) -> decltype( CEREAL_LOAD_MINIMAL_FUNCTION_NAME(                                               \
     820             :               std::declval<AA const &>(), std::declval<TT&>(), NoConvertConstRef<UU>() versioned ), yes() );                 \
     821             :         template <class, class, class> static no test2( ... );                                                               \
     822             :         static const bool valid = std::is_same<decltype( test2<T, A, U>( 0 ) ), yes>::value;                                 \
     823             :                                                                                                                              \
     824             :         template <class TT, class AA>                                                                                        \
     825             :         static auto test3(int) -> decltype( CEREAL_LOAD_MINIMAL_FUNCTION_NAME(                                               \
     826             :               std::declval<AA const &>(), NoConvertRef<TT>(), AnyConvert() versioned ), yes() );                             \
     827             :         template <class, class> static no test3( ... );                                                                      \
     828             :         static const bool const_valid = std::is_same<decltype( test3<T, A>( 0 ) ), yes>::value;                              \
     829             :       };                                                                                                                     \
     830             :                                                                                                                              \
     831             :       template <class T, class A, bool Valid>                                                                                \
     832             :       struct has_non_member_##test_name##_wrapper : std::false_type {};                                                      \
     833             :                                                                                                                              \
     834             :       template <class T, class A>                                                                                            \
     835             :       struct has_non_member_##test_name##_wrapper<T, A, true>                                                                \
     836             :       {                                                                                                                      \
     837             :         using AOut = typename detail::get_output_from_input<A>::type;                                                        \
     838             :                                                                                                                              \
     839             :         static_assert( detail::has_non_member_##save_name##_impl<T, AOut>::valid,                                            \
     840             :           "cereal detected non-member " #test_name " but no valid non-member " #save_name ". \n "                            \
     841             :           "cannot evaluate correctness of " #test_name " without valid " #save_name "." );                                   \
     842             :                                                                                                                              \
     843             :         using SaveType = typename detail::get_non_member_##save_name##_type<T, AOut, true>::type;                            \
     844             :         using check = has_non_member_##test_name##_impl<T, A, SaveType>;                                                     \
     845             :         static const bool value = check::exists;                                                                             \
     846             :                                                                                                                              \
     847             :         static_assert( check::valid || !check::exists, "cereal detected different types in corresponding non-member "        \
     848             :             #test_name " and " #save_name " functions. \n "                                                                  \
     849             :             "the paramater to " #test_name " must be a constant reference to the type that " #save_name " returns." );       \
     850             :         static_assert( check::const_valid || !check::exists,                                                                 \
     851             :             "cereal detected an invalid serialization type parameter in non-member " #test_name ".  "                        \
     852             :             #test_name " non-member functions must accept their serialization type by non-const reference" );                \
     853             :       };                                                                                                                     \
     854             :     } /* namespace detail */                                                                                                 \
     855             :                                                                                                                              \
     856             :     template <class T, class A>                                                                                              \
     857             :     struct has_non_member_##test_name : std::integral_constant<bool,                                                         \
     858             :       detail::has_non_member_##test_name##_wrapper<T, A, detail::has_non_member_##test_name##_impl<T, A>::exists>::value> {};
     859             : 
     860             :     // ######################################################################
     861             :     // Non-Member Load Minimal
     862             :     CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST(load_minimal, save_minimal, )
     863             : 
     864             :     // ######################################################################
     865             :     // Non-Member Load Minimal (versioned)
     866             :     CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST(versioned_load_minimal, versioned_save_minimal, CEREAL_MAKE_VERSIONED_TEST)
     867             : 
     868             :     // ######################################################################
     869             :     #undef CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST
     870             : 
     871             :     // ######################################################################
     872             :     //! Member load and construct check
     873             :     template<typename T, typename A>
     874             :     struct has_member_load_and_construct : std::integral_constant<bool,
     875             :       std::is_same<decltype( access::load_and_construct<T>( std::declval<A&>(), std::declval< ::cereal::construct<T>&>() ) ), void>::value>
     876             :     { };
     877             : 
     878             :     // ######################################################################
     879             :     //! Member load and construct check (versioned)
     880             :     template<typename T, typename A>
     881             :     struct has_member_versioned_load_and_construct : std::integral_constant<bool,
     882             :       std::is_same<decltype( access::load_and_construct<T>( std::declval<A&>(), std::declval< ::cereal::construct<T>&>(), 0 ) ), void>::value>
     883             :     { };
     884             : 
     885             :     // ######################################################################
     886             :     //! Creates a test for whether a non-member load_and_construct specialization exists
     887             :     /*! This creates a class derived from std::integral_constant that will be true if
     888             :         the type has the proper non-member function for the given archive. */
     889             :     #define CEREAL_MAKE_HAS_NON_MEMBER_LOAD_AND_CONSTRUCT_TEST(test_name, versioned)                                            \
     890             :     namespace detail                                                                                                            \
     891             :     {                                                                                                                           \
     892             :       template <class T, class A>                                                                                               \
     893             :       struct has_non_member_##test_name##_impl                                                                                  \
     894             :       {                                                                                                                         \
     895             :         template <class TT, class AA>                                                                                           \
     896             :         static auto test(int) -> decltype( LoadAndConstruct<TT>::load_and_construct(                                            \
     897             :                                            std::declval<AA&>(), std::declval< ::cereal::construct<TT>&>() versioned ), yes());  \
     898             :         template <class, class>                                                                                                 \
     899             :         static no test( ... );                                                                                                  \
     900             :         static const bool value = std::is_same<decltype( test<T, A>( 0 ) ), yes>::value;                                        \
     901             :       };                                                                                                                        \
     902             :     } /* end namespace detail */                                                                                                \
     903             :     template <class T, class A>                                                                                                 \
     904             :     struct has_non_member_##test_name : std::integral_constant<bool, detail::has_non_member_##test_name##_impl<T, A>::value> {};
     905             : 
     906             :     // ######################################################################
     907             :     //! Non member load and construct check
     908             :     CEREAL_MAKE_HAS_NON_MEMBER_LOAD_AND_CONSTRUCT_TEST(load_and_construct, )
     909             : 
     910             :     // ######################################################################
     911             :     //! Non member load and construct check (versioned)
     912             :     CEREAL_MAKE_HAS_NON_MEMBER_LOAD_AND_CONSTRUCT_TEST(versioned_load_and_construct, CEREAL_MAKE_VERSIONED_TEST)
     913             : 
     914             :     // ######################################################################
     915             :     //! Has either a member or non member load and construct
     916             :     template<typename T, typename A>
     917             :     struct has_load_and_construct : std::integral_constant<bool,
     918             :       has_member_load_and_construct<T, A>::value || has_non_member_load_and_construct<T, A>::value ||
     919             :       has_member_versioned_load_and_construct<T, A>::value || has_non_member_versioned_load_and_construct<T, A>::value>
     920             :     { };
     921             : 
     922             :     // ######################################################################
     923             :     #undef CEREAL_MAKE_HAS_NON_MEMBER_LOAD_AND_CONSTRUCT_TEST
     924             : 
     925             :     // ######################################################################
     926             :     // End of serialization existence tests
     927             :     #undef CEREAL_MAKE_VERSIONED_TEST
     928             : 
     929             :     // ######################################################################
     930             :     template <class T, class InputArchive, class OutputArchive>
     931             :     struct has_member_split : std::integral_constant<bool,
     932             :       (has_member_load<T, InputArchive>::value && has_member_save<T, OutputArchive>::value) ||
     933             :       (has_member_versioned_load<T, InputArchive>::value && has_member_versioned_save<T, OutputArchive>::value)> {};
     934             : 
     935             :     // ######################################################################
     936             :     template <class T, class InputArchive, class OutputArchive>
     937             :     struct has_non_member_split : std::integral_constant<bool,
     938             :       (has_non_member_load<T, InputArchive>::value && has_non_member_save<T, OutputArchive>::value) ||
     939             :       (has_non_member_versioned_load<T, InputArchive>::value && has_non_member_versioned_save<T, OutputArchive>::value)> {};
     940             : 
     941             :     // ######################################################################
     942             :     template <class T, class OutputArchive>
     943             :     struct has_invalid_output_versioning : std::integral_constant<bool,
     944             :       (has_member_versioned_save<T, OutputArchive>::value && has_member_save<T, OutputArchive>::value) ||
     945             :       (has_non_member_versioned_save<T, OutputArchive>::value && has_non_member_save<T, OutputArchive>::value) ||
     946             :       (has_member_versioned_serialize<T, OutputArchive>::value && has_member_serialize<T, OutputArchive>::value) ||
     947             :       (has_non_member_versioned_serialize<T, OutputArchive>::value && has_non_member_serialize<T, OutputArchive>::value) ||
     948             :       (has_member_versioned_save_minimal<T, OutputArchive>::value && has_member_save_minimal<T, OutputArchive>::value) ||
     949             :       (has_non_member_versioned_save_minimal<T, OutputArchive>::value &&  has_non_member_save_minimal<T, OutputArchive>::value)> {};
     950             : 
     951             :     // ######################################################################
     952             :     template <class T, class InputArchive>
     953             :     struct has_invalid_input_versioning : std::integral_constant<bool,
     954             :       (has_member_versioned_load<T, InputArchive>::value && has_member_load<T, InputArchive>::value) ||
     955             :       (has_non_member_versioned_load<T, InputArchive>::value && has_non_member_load<T, InputArchive>::value) ||
     956             :       (has_member_versioned_serialize<T, InputArchive>::value && has_member_serialize<T, InputArchive>::value) ||
     957             :       (has_non_member_versioned_serialize<T, InputArchive>::value && has_non_member_serialize<T, InputArchive>::value) ||
     958             :       (has_member_versioned_load_minimal<T, InputArchive>::value && has_member_load_minimal<T, InputArchive>::value) ||
     959             :       (has_non_member_versioned_load_minimal<T, InputArchive>::value &&  has_non_member_load_minimal<T, InputArchive>::value)> {};
     960             : 
     961             :     // ######################################################################
     962             :     namespace detail
     963             :     {
     964             :       //! Create a test for a cereal::specialization entry
     965             :       #define CEREAL_MAKE_IS_SPECIALIZED_IMPL(name)                                          \
     966             :       template <class T, class A>                                                            \
     967             :       struct is_specialized_##name : std::integral_constant<bool,                            \
     968             :         !std::is_base_of<std::false_type, specialize<A, T, specialization::name>>::value> {}
     969             : 
     970             :       CEREAL_MAKE_IS_SPECIALIZED_IMPL(member_serialize);
     971             :       CEREAL_MAKE_IS_SPECIALIZED_IMPL(member_load_save);
     972             :       CEREAL_MAKE_IS_SPECIALIZED_IMPL(member_load_save_minimal);
     973             :       CEREAL_MAKE_IS_SPECIALIZED_IMPL(non_member_serialize);
     974             :       CEREAL_MAKE_IS_SPECIALIZED_IMPL(non_member_load_save);
     975             :       CEREAL_MAKE_IS_SPECIALIZED_IMPL(non_member_load_save_minimal);
     976             : 
     977             :       #undef CEREAL_MAKE_IS_SPECIALIZED_IMPL
     978             : 
     979             :       //! Number of specializations detected
     980             :       template <class T, class A>
     981             :       struct count_specializations : std::integral_constant<int,
     982             :         is_specialized_member_serialize<T, A>::value +
     983             :         is_specialized_member_load_save<T, A>::value +
     984             :         is_specialized_member_load_save_minimal<T, A>::value +
     985             :         is_specialized_non_member_serialize<T, A>::value +
     986             :         is_specialized_non_member_load_save<T, A>::value +
     987             :         is_specialized_non_member_load_save_minimal<T, A>::value> {};
     988             :     } // namespace detail
     989             : 
     990             :     //! Check if any specialization exists for a type
     991             :     template <class T, class A>
     992             :     struct is_specialized : std::integral_constant<bool,
     993             :       detail::is_specialized_member_serialize<T, A>::value ||
     994             :       detail::is_specialized_member_load_save<T, A>::value ||
     995             :       detail::is_specialized_member_load_save_minimal<T, A>::value ||
     996             :       detail::is_specialized_non_member_serialize<T, A>::value ||
     997             :       detail::is_specialized_non_member_load_save<T, A>::value ||
     998             :       detail::is_specialized_non_member_load_save_minimal<T, A>::value>
     999             :     {
    1000             :       static_assert(detail::count_specializations<T, A>::value <= 1, "More than one explicit specialization detected for type.");
    1001             :     };
    1002             : 
    1003             :     //! Create the static assertion for some specialization
    1004             :     /*! This assertion will fail if the type is indeed specialized and does not have the appropriate
    1005             :         type of serialization functions */
    1006             :     #define CEREAL_MAKE_IS_SPECIALIZED_ASSERT(name, versioned_name, print_name, spec_name)                      \
    1007             :     static_assert( (is_specialized<T, A>::value && detail::is_specialized_##spec_name<T, A>::value &&           \
    1008             :                    (has_##name<T, A>::value || has_##versioned_name<T, A>::value))                              \
    1009             :                    || !(is_specialized<T, A>::value && detail::is_specialized_##spec_name<T, A>::value),        \
    1010             :                    "cereal detected " #print_name " specialization but no " #print_name " serialize function" )
    1011             : 
    1012             :     //! Generates a test for specialization for versioned and unversioned functions
    1013             :     /*! This creates checks that can be queried to see if a given type of serialization function
    1014             :         has been specialized for this type */
    1015             :     #define CEREAL_MAKE_IS_SPECIALIZED(name, versioned_name, spec_name)                     \
    1016             :     template <class T, class A>                                                             \
    1017             :     struct is_specialized_##name : std::integral_constant<bool,                             \
    1018             :       is_specialized<T, A>::value && detail::is_specialized_##spec_name<T, A>::value>       \
    1019             :     { CEREAL_MAKE_IS_SPECIALIZED_ASSERT(name, versioned_name, name, spec_name); };          \
    1020             :     template <class T, class A>                                                             \
    1021             :     struct is_specialized_##versioned_name : std::integral_constant<bool,                   \
    1022             :       is_specialized<T, A>::value && detail::is_specialized_##spec_name<T, A>::value>       \
    1023             :     { CEREAL_MAKE_IS_SPECIALIZED_ASSERT(name, versioned_name, versioned_name, spec_name); }
    1024             : 
    1025             :     CEREAL_MAKE_IS_SPECIALIZED(member_serialize, member_versioned_serialize, member_serialize);
    1026             :     CEREAL_MAKE_IS_SPECIALIZED(non_member_serialize, non_member_versioned_serialize, non_member_serialize);
    1027             : 
    1028             :     CEREAL_MAKE_IS_SPECIALIZED(member_save, member_versioned_save, member_load_save);
    1029             :     CEREAL_MAKE_IS_SPECIALIZED(non_member_save, non_member_versioned_save, non_member_load_save);
    1030             :     CEREAL_MAKE_IS_SPECIALIZED(member_load, member_versioned_load, member_load_save);
    1031             :     CEREAL_MAKE_IS_SPECIALIZED(non_member_load, non_member_versioned_load, non_member_load_save);
    1032             : 
    1033             :     CEREAL_MAKE_IS_SPECIALIZED(member_save_minimal, member_versioned_save_minimal, member_load_save_minimal);
    1034             :     CEREAL_MAKE_IS_SPECIALIZED(non_member_save_minimal, non_member_versioned_save_minimal, non_member_load_save_minimal);
    1035             :     CEREAL_MAKE_IS_SPECIALIZED(member_load_minimal, member_versioned_load_minimal, member_load_save_minimal);
    1036             :     CEREAL_MAKE_IS_SPECIALIZED(non_member_load_minimal, non_member_versioned_load_minimal, non_member_load_save_minimal);
    1037             : 
    1038             :     #undef CEREAL_MAKE_IS_SPECIALIZED_ASSERT
    1039             :     #undef CEREAL_MAKE_IS_SPECIALIZED
    1040             : 
    1041             :     // ######################################################################
    1042             :     // detects if a type has any active minimal output serialization
    1043             :     template <class T, class OutputArchive>
    1044             :     struct has_minimal_output_serialization : std::integral_constant<bool,
    1045             :       is_specialized_member_save_minimal<T, OutputArchive>::value ||
    1046             :       ((has_member_save_minimal<T, OutputArchive>::value ||
    1047             :         has_non_member_save_minimal<T, OutputArchive>::value ||
    1048             :         has_member_versioned_save_minimal<T, OutputArchive>::value ||
    1049             :         has_non_member_versioned_save_minimal<T, OutputArchive>::value) &&
    1050             :        !(is_specialized_member_serialize<T, OutputArchive>::value ||
    1051             :          is_specialized_member_save<T, OutputArchive>::value))> {};
    1052             : 
    1053             :     // ######################################################################
    1054             :     // detects if a type has any active minimal input serialization
    1055             :     template <class T, class InputArchive>
    1056             :     struct has_minimal_input_serialization : std::integral_constant<bool,
    1057             :       is_specialized_member_load_minimal<T, InputArchive>::value ||
    1058             :       ((has_member_load_minimal<T, InputArchive>::value ||
    1059             :         has_non_member_load_minimal<T, InputArchive>::value ||
    1060             :         has_member_versioned_load_minimal<T, InputArchive>::value ||
    1061             :         has_non_member_versioned_load_minimal<T, InputArchive>::value) &&
    1062             :        !(is_specialized_member_serialize<T, InputArchive>::value ||
    1063             :          is_specialized_member_load<T, InputArchive>::value))> {};
    1064             : 
    1065             :     // ######################################################################
    1066             :     namespace detail
    1067             :     {
    1068             :       //! The number of output serialization functions available
    1069             :       /*! If specialization is being used, we'll count only those; otherwise we'll count everything */
    1070             :       template <class T, class OutputArchive>
    1071             :       struct count_output_serializers : std::integral_constant<int,
    1072             :         count_specializations<T, OutputArchive>::value ? count_specializations<T, OutputArchive>::value :
    1073             :         has_member_save<T, OutputArchive>::value +
    1074             :         has_non_member_save<T, OutputArchive>::value +
    1075             :         has_member_serialize<T, OutputArchive>::value +
    1076             :         has_non_member_serialize<T, OutputArchive>::value +
    1077             :         has_member_save_minimal<T, OutputArchive>::value +
    1078             :         has_non_member_save_minimal<T, OutputArchive>::value +
    1079             :         /*-versioned---------------------------------------------------------*/
    1080             :         has_member_versioned_save<T, OutputArchive>::value +
    1081             :         has_non_member_versioned_save<T, OutputArchive>::value +
    1082             :         has_member_versioned_serialize<T, OutputArchive>::value +
    1083             :         has_non_member_versioned_serialize<T, OutputArchive>::value +
    1084             :         has_member_versioned_save_minimal<T, OutputArchive>::value +
    1085             :         has_non_member_versioned_save_minimal<T, OutputArchive>::value> {};
    1086             :     }
    1087             : 
    1088             :     template <class T, class OutputArchive>
    1089             :     struct is_output_serializable : std::integral_constant<bool,
    1090             :       detail::count_output_serializers<T, OutputArchive>::value == 1> {};
    1091             : 
    1092             :     // ######################################################################
    1093             :     namespace detail
    1094             :     {
    1095             :       //! The number of input serialization functions available
    1096             :       /*! If specialization is being used, we'll count only those; otherwise we'll count everything */
    1097             :       template <class T, class InputArchive>
    1098             :       struct count_input_serializers : std::integral_constant<int,
    1099             :         count_specializations<T, InputArchive>::value ? count_specializations<T, InputArchive>::value :
    1100             :         has_member_load<T, InputArchive>::value +
    1101             :         has_non_member_load<T, InputArchive>::value +
    1102             :         has_member_serialize<T, InputArchive>::value +
    1103             :         has_non_member_serialize<T, InputArchive>::value +
    1104             :         has_member_load_minimal<T, InputArchive>::value +
    1105             :         has_non_member_load_minimal<T, InputArchive>::value +
    1106             :         /*-versioned---------------------------------------------------------*/
    1107             :         has_member_versioned_load<T, InputArchive>::value +
    1108             :         has_non_member_versioned_load<T, InputArchive>::value +
    1109             :         has_member_versioned_serialize<T, InputArchive>::value +
    1110             :         has_non_member_versioned_serialize<T, InputArchive>::value +
    1111             :         has_member_versioned_load_minimal<T, InputArchive>::value +
    1112             :         has_non_member_versioned_load_minimal<T, InputArchive>::value> {};
    1113             :     }
    1114             : 
    1115             :     template <class T, class InputArchive>
    1116             :     struct is_input_serializable : std::integral_constant<bool,
    1117             :       detail::count_input_serializers<T, InputArchive>::value == 1> {};
    1118             : 
    1119             :     // ######################################################################
    1120             :     // Base Class Support
    1121             :     namespace detail
    1122             :     {
    1123             :       struct base_class_id
    1124             :       {
    1125             :         template<class T>
    1126        3200 :           base_class_id(T const * const t) :
    1127             :           type(typeid(T)),
    1128             :           ptr(t),
    1129        3200 :           hash(std::hash<std::type_index>()(typeid(T)) ^ (std::hash<void const *>()(t) << 1))
    1130        3200 :           { }
    1131             : 
    1132        1600 :           bool operator==(base_class_id const & other) const
    1133        1600 :           { return (type == other.type) && (ptr == other.ptr); }
    1134             : 
    1135             :           std::type_index type;
    1136             :           void const * ptr;
    1137             :           size_t hash;
    1138             :       };
    1139       33904 :       struct base_class_id_hash { size_t operator()(base_class_id const & id) const { return id.hash; }  };
    1140             :     } // namespace detail
    1141             : 
    1142             :     namespace detail
    1143             :     {
    1144             :       //! Common base type for base class casting
    1145        8000 :       struct BaseCastBase {};
    1146             : 
    1147             :       template <class>
    1148             :       struct get_base_class;
    1149             : 
    1150             :       template <template<typename> class Cast, class Base>
    1151             :       struct get_base_class<Cast<Base>>
    1152             :       {
    1153             :         using type = Base;
    1154             :       };
    1155             : 
    1156             :       //! Base class cast, behave as the test
    1157             :       template <class Cast, template<class, class> class Test, class Archive,
    1158             :                 bool IsBaseCast = std::is_base_of<BaseCastBase, Cast>::value>
    1159             :       struct has_minimal_base_class_serialization_impl : Test<typename get_base_class<Cast>::type, Archive>
    1160             :       { };
    1161             : 
    1162             :       //! Not a base class cast
    1163             :       template <class Cast, template<class, class> class Test, class Archive>
    1164             :       struct has_minimal_base_class_serialization_impl<Cast,Test, Archive, false> : std::false_type
    1165             :       { };
    1166             :     }
    1167             : 
    1168             :     //! Checks to see if the base class used in a cast has a minimal serialization
    1169             :     /*! @tparam Cast Either base_class or virtual_base_class wrapped type
    1170             :         @tparam Test A has_minimal test (for either input or output)
    1171             :         @tparam Archive The archive to use with the test */
    1172             :     template <class Cast, template<class, class> class Test, class Archive>
    1173             :     struct has_minimal_base_class_serialization : detail::has_minimal_base_class_serialization_impl<Cast, Test, Archive>
    1174             :     { };
    1175             : 
    1176             : 
    1177             :     // ######################################################################
    1178             :     namespace detail
    1179             :     {
    1180             :       struct shared_from_this_wrapper
    1181             :       {
    1182             :         template <class U>
    1183             :         static auto (check)( U const & t ) -> decltype( ::cereal::access::shared_from_this(t), std::true_type() );
    1184             : 
    1185             :         static auto (check)( ... ) -> decltype( std::false_type() );
    1186             : 
    1187             :         template <class U>
    1188             :         static auto get( U const & t ) -> decltype( t.shared_from_this() );
    1189             :       };
    1190             :     }
    1191             : 
    1192             :     //! Determine if T or any base class of T has inherited from std::enable_shared_from_this
    1193             :     template<class T>
    1194             :     struct has_shared_from_this : decltype((detail::shared_from_this_wrapper::check)(std::declval<T>()))
    1195             :     { };
    1196             : 
    1197             :     //! Get the type of the base class of T which inherited from std::enable_shared_from_this
    1198             :     template <class T>
    1199             :     struct get_shared_from_this_base
    1200             :     {
    1201             :       private:
    1202             :         using PtrType = decltype(detail::shared_from_this_wrapper::get(std::declval<T>()));
    1203             :       public:
    1204             :         //! The type of the base of T that inherited from std::enable_shared_from_this
    1205             :         using type = typename std::decay<typename PtrType::element_type>::type;
    1206             :     };
    1207             : 
    1208             :     // ######################################################################
    1209             :     //! Extracts the true type from something possibly wrapped in a cereal NoConvert
    1210             :     /*! Internally cereal uses some wrapper classes to test the validity of non-member
    1211             :         minimal load and save functions.  This can interfere with user type traits on
    1212             :         templated load and save minimal functions.  To get to the correct underlying type,
    1213             :         users should use strip_minimal when performing any enable_if type type trait checks.
    1214             : 
    1215             :         See the enum serialization in types/common.hpp for an example of using this */
    1216             :     template <class T, bool IsCerealMinimalTrait = std::is_base_of<detail::NoConvertBase, T>::value>
    1217             :     struct strip_minimal
    1218             :     {
    1219             :       using type = T;
    1220             :     };
    1221             : 
    1222             :     //! Specialization for types wrapped in a NoConvert
    1223             :     template <class T>
    1224             :     struct strip_minimal<T, true>
    1225             :     {
    1226             :       using type = typename T::type;
    1227             :     };
    1228             : 
    1229             :     // ######################################################################
    1230             :     //! Determines whether the class T can be default constructed by cereal::access
    1231             :     template <class T>
    1232             :     struct is_default_constructible
    1233             :     {
    1234             :       #ifdef CEREAL_OLDER_GCC
    1235             :       template <class TT, class SFINAE = void>
    1236             :       struct test : no {};
    1237             :       template <class TT>
    1238             :       struct test<TT, typename detail::Void< decltype( cereal::access::construct<TT>() ) >::type> : yes {};
    1239             :       static const bool value = test<T>();
    1240             :       #else // NOT CEREAL_OLDER_GCC =========================================
    1241             :       template <class TT>
    1242             :       static auto test(int) -> decltype( cereal::access::construct<TT>(), yes());
    1243             :       template <class>
    1244             :       static no test(...);
    1245             :       static const bool value = std::is_same<decltype(test<T>(0)), yes>::value;
    1246             :       #endif // NOT CEREAL_OLDER_GCC
    1247             :     };
    1248             : 
    1249             :     // ######################################################################
    1250             :     namespace detail
    1251             :     {
    1252             :       //! Removes all qualifiers and minimal wrappers from an archive
    1253             :       template <class A>
    1254             :       using decay_archive = typename std::decay<typename strip_minimal<A>::type>::type;
    1255             :     }
    1256             : 
    1257             :     //! Checks if the provided archive type is equal to some cereal archive type
    1258             :     /*! This automatically does things such as std::decay and removing any other wrappers that may be
    1259             :         on the Archive template parameter.
    1260             : 
    1261             :         Example use:
    1262             :         @code{cpp}
    1263             :         // example use to disable a serialization function
    1264             :         template <class Archive, EnableIf<cereal::traits::is_same_archive<Archive, cereal::BinaryOutputArchive>::value> = sfinae>
    1265             :         void save( Archive & ar, MyType const & mt );
    1266             :         @endcode */
    1267             :     template <class ArchiveT, class CerealArchiveT>
    1268             :     struct is_same_archive : std::integral_constant<bool,
    1269             :       std::is_same<detail::decay_archive<ArchiveT>, CerealArchiveT>::value>
    1270             :     { };
    1271             : 
    1272             :     // ######################################################################
    1273             :     //! A macro to use to restrict which types of archives your function will work for.
    1274             :     /*! This requires you to have a template class parameter named Archive and replaces the void return
    1275             :         type for your function.
    1276             : 
    1277             :         INTYPE refers to the input archive type you wish to restrict on.
    1278             :         OUTTYPE refers to the output archive type you wish to restrict on.
    1279             : 
    1280             :         For example, if we want to limit a serialize to only work with binary serialization:
    1281             : 
    1282             :         @code{.cpp}
    1283             :         template <class Archive>
    1284             :         CEREAL_ARCHIVE_RESTRICT(BinaryInputArchive, BinaryOutputArchive)
    1285             :         serialize( Archive & ar, MyCoolType & m )
    1286             :         {
    1287             :           ar & m;
    1288             :         }
    1289             :         @endcode
    1290             : 
    1291             :         If you need to do more restrictions in your enable_if, you will need to do this by hand.
    1292             :      */
    1293             :     #define CEREAL_ARCHIVE_RESTRICT(INTYPE, OUTTYPE) \
    1294             :     typename std::enable_if<cereal::traits::is_same_archive<Archive, INTYPE>::value || cereal::traits::is_same_archive<Archive, OUTTYPE>::value, void>::type
    1295             : 
    1296             :     //! Type traits only struct used to mark an archive as human readable (text based)
    1297             :     /*! Archives that wish to identify as text based/human readable should inherit from
    1298             :         this struct */
    1299       14296 :     struct TextArchive {};
    1300             : 
    1301             :     //! Checks if an archive is a text archive (human readable)
    1302             :     template <class A>
    1303             :     struct is_text_archive : std::integral_constant<bool,
    1304             :       std::is_base_of<TextArchive, detail::decay_archive<A>>::value>
    1305             :     { };
    1306             :   } // namespace traits
    1307             : 
    1308             :   // ######################################################################
    1309             :   namespace detail
    1310             :   {
    1311             :     template <class T, class A,
    1312             :               bool Member = traits::has_member_load_and_construct<T, A>::value,
    1313             :               bool MemberVersioned = traits::has_member_versioned_load_and_construct<T, A>::value,
    1314             :               bool NonMember = traits::has_non_member_load_and_construct<T, A>::value,
    1315             :               bool NonMemberVersioned = traits::has_non_member_versioned_load_and_construct<T, A>::value>
    1316             :     struct Construct
    1317             :     {
    1318             :       static_assert( cereal::traits::detail::delay_static_assert<T>::value,
    1319             :         "cereal found more than one compatible load_and_construct function for the provided type and archive combination. \n\n "
    1320             :         "Types must either have a member load_and_construct function or a non-member specialization of LoadAndConstruct (you may not mix these). \n "
    1321             :         "In addition, you may not mix versioned with non-versioned load_and_construct functions. \n\n " );
    1322             :       static T * load_andor_construct( A & /*ar*/, construct<T> & /*construct*/ )
    1323             :       { return nullptr; }
    1324             :     };
    1325             : 
    1326             :     // no load and construct case
    1327             :     template <class T, class A>
    1328             :     struct Construct<T, A, false, false, false, false>
    1329             :     {
    1330             :       static_assert( ::cereal::traits::is_default_constructible<T>::value,
    1331             :                      "Trying to serialize a an object with no default constructor. \n\n "
    1332             :                      "Types must either be default constructible or define either a member or non member Construct function. \n "
    1333             :                      "Construct functions generally have the signature: \n\n "
    1334             :                      "template <class Archive> \n "
    1335             :                      "static void load_and_construct(Archive & ar, cereal::construct<T> & construct) \n "
    1336             :                      "{ \n "
    1337             :                      "  var a; \n "
    1338             :                      "  ar( a ) \n "
    1339             :                      "  construct( a ); \n "
    1340             :                      "} \n\n" );
    1341       83204 :       static T * load_andor_construct()
    1342       83204 :       { return ::cereal::access::construct<T>(); }
    1343             :     };
    1344             : 
    1345             :     // member non-versioned
    1346             :     template <class T, class A>
    1347             :     struct Construct<T, A, true, false, false, false>
    1348             :     {
    1349        3200 :       static void load_andor_construct( A & ar, construct<T> & construct )
    1350             :       {
    1351        3200 :         access::load_and_construct<T>( ar, construct );
    1352        2800 :       }
    1353             :     };
    1354             : 
    1355             :     // member versioned
    1356             :     template <class T, class A>
    1357             :     struct Construct<T, A, false, true, false, false>
    1358             :     {
    1359         400 :       static void load_andor_construct( A & ar, construct<T> & construct )
    1360             :       {
    1361         400 :         const auto version = ar.template loadClassVersion<T>();
    1362         400 :         access::load_and_construct<T>( ar, construct, version );
    1363         400 :       }
    1364             :     };
    1365             : 
    1366             :     // non-member non-versioned
    1367             :     template <class T, class A>
    1368             :     struct Construct<T, A, false, false, true, false>
    1369             :     {
    1370         800 :       static void load_andor_construct( A & ar, construct<T> & construct )
    1371             :       {
    1372         800 :         LoadAndConstruct<T>::load_and_construct( ar, construct );
    1373         800 :       }
    1374             :     };
    1375             : 
    1376             :     // non-member versioned
    1377             :     template <class T, class A>
    1378             :     struct Construct<T, A, false, false, false, true>
    1379             :     {
    1380         400 :       static void load_andor_construct( A & ar, construct<T> & construct )
    1381             :       {
    1382         400 :         const auto version = ar.template loadClassVersion<T>();
    1383         400 :         LoadAndConstruct<T>::load_and_construct( ar, construct, version );
    1384         400 :       }
    1385             :     };
    1386             :   } // namespace detail
    1387             : } // namespace cereal
    1388             : 
    1389             : #endif // CEREAL_DETAILS_TRAITS_HPP_

Generated by: LCOV version 1.11