add cereal library
[platform/upstream/iotivity.git] / extlibs / cereal / cereal / include / cereal / details / traits.hpp
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/access.hpp>
43
44 namespace cereal
45 {
46   namespace traits
47   {
48     typedef std::true_type yes;
49     typedef std::false_type no;
50
51     namespace detail
52     {
53       //! Used to delay a static_assert until template instantiation
54       template <class T>
55       struct delay_static_assert : std::false_type {};
56
57       #ifdef CEREAL_OLDER_GCC // when VS supports better SFINAE, we can use this as the default
58       template<typename> struct Void { typedef void type; };
59       #endif // CEREAL_OLDER_GCC
60     } // namespace detail
61
62     //! Creates a test for whether a non const member function exists
63     /*! This creates a class derived from std::integral_constant that will be true if
64         the type has the proper member function for the given archive. */
65     #ifdef CEREAL_OLDER_GCC
66     #define CEREAL_MAKE_HAS_MEMBER_TEST(name)                                                                                      \
67     template <class T, class A, class SFINAE = void>                                                                               \
68     struct has_member_##name : no {};                                                                                              \
69     template <class T, class A>                                                                                                    \
70     struct has_member_##name<T, A,                                                                                                 \
71       typename detail::Void< decltype( cereal::access::member_##name( std::declval<A&>(), std::declval<T&>() ) ) >::type> : yes {}
72     #else // NOT CEREAL_OLDER_GCC
73     #define CEREAL_MAKE_HAS_MEMBER_TEST(name)                                                                                      \
74     namespace detail                                                                                                               \
75     {                                                                                                                              \
76       template <class T, class A>                                                                                                  \
77       struct has_member_##name##_impl                                                                                              \
78       {                                                                                                                            \
79         template <class TT, class AA>                                                                                              \
80         static auto test(int) -> decltype( cereal::access::member_##name( std::declval<AA&>(), std::declval<TT&>() ), yes());      \
81         template <class, class>                                                                                                    \
82         static no test(...);                                                                                                       \
83         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;                                               \
84       };                                                                                                                           \
85     } /* end namespace detail */                                                                                                   \
86     template <class T, class A>                                                                                                    \
87     struct has_member_##name : std::integral_constant<bool, detail::has_member_##name##_impl<T, A>::value> {}
88     #endif // NOT CEREAL_OLDER_GCC
89
90     //! Creates a test for whether a non const non-member function exists
91     /*! This creates a class derived from std::integral_constant that will be true if
92         the type has the proper non-member function for the given archive. */
93     #define CEREAL_MAKE_HAS_NON_MEMBER_TEST(name)                                                                                  \
94     namespace detail                                                                                                               \
95     {                                                                                                                              \
96       template <class T, class A>                                                                                                  \
97       struct has_non_member_##name##_impl                                                                                          \
98       {                                                                                                                            \
99         template <class TT, class AA>                                                                                              \
100         static auto test(int) -> decltype( name( std::declval<AA&>(), std::declval<TT&>() ), yes());                               \
101         template <class, class>                                                                                                    \
102         static no test( ... );                                                                                                     \
103         static const bool value = std::is_same<decltype( test<T, A>( 0 ) ), yes>::value;                                           \
104       };                                                                                                                           \
105     } /* end namespace detail */                                                                                                   \
106     template <class T, class A>                                                                                                    \
107     struct has_non_member_##name : std::integral_constant<bool, detail::has_non_member_##name##_impl<T, A>::value> {}
108
109     //! Creates a test for whether a non const member function exists with a version parameter
110     /*! This creates a class derived from std::integral_constant that will be true if
111         the type has the proper member function for the given archive. */
112     #ifdef CEREAL_OLDER_GCC
113     #define CEREAL_MAKE_HAS_MEMBER_VERSIONED_TEST(name)                                                                            \
114     template <class T, class A, class SFINAE = void>                                                                               \
115     struct has_member_versioned_##name : no {};                                                                                    \
116     template <class T, class A>                                                                                                    \
117     struct has_member_versioned_##name<T, A,                                                                                       \
118       typename detail::Void< decltype( cereal::access::member_##name( std::declval<A&>(), std::declval<T&>(), 0 ) ) >::type> : yes {}
119     #else // NOT CEREAL_OLDER_GCC
120     #define CEREAL_MAKE_HAS_MEMBER_VERSIONED_TEST(name)                                                                            \
121     namespace detail                                                                                                               \
122     {                                                                                                                              \
123       template <class T, class A>                                                                                                  \
124       struct has_member_versioned_##name##_impl                                                                                    \
125       {                                                                                                                            \
126         template <class TT, class AA>                                                                                              \
127         static auto test(int) -> decltype( cereal::access::member_##name( std::declval<AA&>(), std::declval<TT&>(), 0 ), yes());   \
128         template <class, class>                                                                                                    \
129         static no test(...);                                                                                                       \
130         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;                                               \
131       };                                                                                                                           \
132     } /* end namespace detail */                                                                                                   \
133     template <class T, class A>                                                                                                    \
134     struct has_member_versioned_##name : std::integral_constant<bool, detail::has_member_versioned_##name##_impl<T, A>::value> {}
135     #endif // NOT CEREAL_OLDER_GCC
136
137     //! Creates a test for whether a non const non-member function exists with a version parameter
138     /*! This creates a class derived from std::integral_constant that will be true if
139         the type has the proper non-member function for the given archive. */
140     #define CEREAL_MAKE_HAS_NON_MEMBER_VERSIONED_TEST(name)                                                                        \
141     namespace detail                                                                                                               \
142     {                                                                                                                              \
143       template <class T, class A>                                                                                                  \
144       struct has_non_member_versioned_##name##_impl                                                                                \
145       {                                                                                                                            \
146         template <class TT, class AA>                                                                                              \
147         static auto test(int) -> decltype( name( std::declval<AA&>(), std::declval<TT&>(), 0 ), yes());                            \
148         template <class, class>                                                                                                    \
149         static no test( ... );                                                                                                     \
150         static const bool value = std::is_same<decltype( test<T, A>( 0 ) ), yes>::value;                                           \
151       };                                                                                                                           \
152     } /* end namespace detail */                                                                                                   \
153     template <class T, class A>                                                                                                    \
154     struct has_non_member_versioned_##name : std::integral_constant<bool, detail::has_non_member_versioned_##name##_impl<T, A>::value> {}
155
156     // ######################################################################
157     // Member load_and_construct
158     template<typename T, typename A>
159     struct has_member_load_and_construct :
160       std::integral_constant<bool, std::is_same<decltype( access::load_and_construct<T>( std::declval<A&>(), std::declval< ::cereal::construct<T>&>() ) ), void>::value> {};
161
162     // ######################################################################
163     // Non Member load_and_construct
164     template<typename T, typename A>
165     struct has_non_member_load_and_construct : std::integral_constant<bool,
166       std::is_same<decltype( LoadAndConstruct<T>::load_and_construct( std::declval<A&>(), std::declval< ::cereal::construct<T>&>() ) ), void>::value> {};
167
168     // ######################################################################
169     // Has either a member or non member allocate
170     template<typename T, typename A>
171     struct has_load_and_construct : std::integral_constant<bool,
172       has_member_load_and_construct<T, A>::value || has_non_member_load_and_construct<T, A>::value>
173     { };
174
175     // ######################################################################
176     // Member Serialize
177     CEREAL_MAKE_HAS_MEMBER_TEST(serialize);
178
179     // ######################################################################
180     // Member Serialize (versioned)
181     CEREAL_MAKE_HAS_MEMBER_VERSIONED_TEST(serialize);
182
183     // ######################################################################
184     // Non Member Serialize
185     CEREAL_MAKE_HAS_NON_MEMBER_TEST(serialize);
186
187     // ######################################################################
188     // Non Member Serialize (versioned)
189     CEREAL_MAKE_HAS_NON_MEMBER_VERSIONED_TEST(serialize);
190
191     // ######################################################################
192     // Member Load
193     CEREAL_MAKE_HAS_MEMBER_TEST(load);
194
195     // ######################################################################
196     // Member Load (versioned)
197     CEREAL_MAKE_HAS_MEMBER_VERSIONED_TEST(load);
198
199     // ######################################################################
200     // Non Member Load
201     CEREAL_MAKE_HAS_NON_MEMBER_TEST(load);
202
203     // ######################################################################
204     // Non Member Load (versioned)
205     CEREAL_MAKE_HAS_NON_MEMBER_VERSIONED_TEST(load);
206
207     // ######################################################################
208     // Member Save
209     namespace detail
210     {
211       template <class T, class A>
212       struct has_member_save_impl
213       {
214         #ifdef CEREAL_OLDER_GCC
215         template <class TT, class AA, class SFINAE = void>
216         struct test : no {};
217         template <class TT, class AA>
218         struct test<TT, AA,
219           typename detail::Void< decltype( cereal::access::member_save( std::declval<AA&>(), std::declval<TT const &>() ) ) >::type> : yes {};
220         static const bool value = test<T, A>();
221
222         template <class TT, class AA, class SFINAE = void>
223         struct test2 : no {};
224         template <class TT, class AA>
225         struct test2<TT, AA,
226           typename detail::Void< decltype( cereal::access::member_save_non_const( std::declval<AA&>(), std::declval<typename std::remove_const<TT>::type&>() ) ) >::type> : yes {};
227         static const bool not_const_type = test2<T, A>();
228         #else // NOT CEREAL_OLDER_GCC =========================================
229         template <class TT, class AA>
230         static auto test(int) -> decltype( cereal::access::member_save( std::declval<AA&>(), std::declval<TT const &>() ), yes());
231         template <class, class>
232         static no test(...);
233         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
234
235         template <class TT, class AA>
236         static auto test2(int) -> decltype( cereal::access::member_save_non_const( std::declval<AA &>(), std::declval<typename std::remove_const<TT>::type&>() ), yes());
237         template <class, class>
238         static no test2(...);
239         static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value;
240         #endif // NOT CEREAL_OLDER_GCC
241       };
242     } // end namespace detail
243
244     template <class T, class A>
245     struct has_member_save : std::integral_constant<bool, detail::has_member_save_impl<T, A>::value>
246     {
247       typedef typename detail::has_member_save_impl<T, A> check;
248       static_assert( check::value || !check::not_const_type,
249         "cereal detected a non-const save. \n "
250         "save member functions must always be const" );
251     };
252
253     // ######################################################################
254     // Member Save (versioned)
255     namespace detail
256     {
257       template <class T, class A>
258       struct has_member_versioned_save_impl
259       {
260         #ifdef CEREAL_OLDER_GCC
261         template <class TT, class AA, class SFINAE = void>
262         struct test : no {};
263         template <class TT, class AA>
264         struct test<TT, AA,
265           typename detail::Void< decltype( cereal::access::member_save( std::declval<AA&>(), std::declval<TT const &>(), 0 ) ) >::type> : yes {};
266         static const bool value = test<T, A>();
267
268         template <class TT, class AA, class SFINAE = void>
269         struct test2 : no {};
270         template <class TT, class AA>
271         struct test2<TT, AA,
272           typename detail::Void< decltype( cereal::access::member_save_non_const( std::declval<AA&>(), std::declval<typename std::remove_const<TT>::type&>(), 0 ) ) >::type> : yes {};
273         static const bool not_const_type = test2<T, A>();
274         #else // NOT CEREAL_OLDER_GCC =========================================
275         template <class TT, class AA>
276         static auto test(int) -> decltype( cereal::access::member_save( std::declval<AA&>(), std::declval<TT const &>(), 0 ), yes());
277         template <class, class>
278         static no test(...);
279         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
280
281         template <class TT, class AA>
282         static auto test2(int) -> decltype( cereal::access::member_save_non_const( std::declval<AA &>(), std::declval<typename std::remove_const<TT>::type&>(), 0 ), yes());
283         template <class, class>
284         static no test2(...);
285         static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value;
286         #endif // NOT_CEREAL_OLDER_GCC
287       };
288     } // end namespace detail
289
290     template <class T, class A>
291     struct has_member_versioned_save : std::integral_constant<bool, detail::has_member_versioned_save_impl<T, A>::value>
292     {
293       typedef typename detail::has_member_versioned_save_impl<T, A> check;
294       static_assert( check::value || !check::not_const_type,
295         "cereal detected a versioned non-const save. \n "
296         "save member functions must always be const" );
297     };
298
299     // ######################################################################
300     // Non-Member Save
301     namespace detail
302     {
303       template <class T, class A>
304       struct has_non_member_save_impl
305       {
306         template <class TT, class AA>
307         static auto test(int) -> decltype( save( std::declval<AA&>(), std::declval<TT const &>() ), yes());
308         template <class, class>
309         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( save( std::declval<AA &>(), std::declval<typename std::remove_const<TT>::type&>() ), yes());
314         template <class, class>
315         static no test2(...);
316         static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value;
317       };
318     } // end namespace detail
319
320     template <class T, class A>
321     struct has_non_member_save : std::integral_constant<bool, detail::has_non_member_save_impl<T, A>::value>
322     {
323       typedef typename detail::has_non_member_save_impl<T, A> check;
324       static_assert( check::value || !check::not_const_type,
325         "cereal detected a non-const type parameter in non-member save. \n "
326         "save non-member functions must always pass their types as const" );
327     };
328
329     // ######################################################################
330     // Non-Member Save (versioned)
331     namespace detail
332     {
333       template <class T, class A>
334       struct has_non_member_versioned_save_impl
335       {
336         template <class TT, class AA>
337         static auto test(int) -> decltype( save( std::declval<AA&>(), std::declval<TT const &>(), 0 ), yes());
338         template <class, class>
339         static no test(...);
340         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
341
342         template <class TT, class AA>
343         static auto test2(int) -> decltype( save( std::declval<AA &>(), std::declval<typename std::remove_const<TT>::type&>(), 0 ), yes());
344         template <class, class>
345         static no test2(...);
346         static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value;
347       };
348     } // end namespace detail
349
350     template <class T, class A>
351     struct has_non_member_versioned_save : std::integral_constant<bool, detail::has_non_member_versioned_save_impl<T, A>::value>
352     {
353       typedef typename detail::has_non_member_versioned_save_impl<T, A> check;
354       static_assert( check::value || !check::not_const_type,
355         "cereal detected a non-const type parameter in versioned non-member save. \n "
356         "save non-member functions must always pass their types as const" );
357     };
358
359     // ######################################################################
360     // Minimal Utilities
361     namespace detail
362     {
363       // Determines if the provided type is an std::string
364       template <class> struct is_string : std::false_type {};
365
366       template <class CharT, class Traits, class Alloc>
367       struct is_string<std::basic_string<CharT, Traits, Alloc>> : std::true_type {};
368     }
369
370     // Determines if the type is valid for use with a minimal serialize function
371     template <class T>
372     struct is_minimal_type : std::integral_constant<bool, detail::is_string<T>::value ||
373       std::is_arithmetic<T>::value> {};
374
375     // ######################################################################
376     // Member Save Minimal
377     namespace detail
378     {
379       template <class T, class A>
380       struct has_member_save_minimal_impl
381       {
382         #ifdef CEREAL_OLDER_GCC
383         template <class TT, class AA, class SFINAE = void>
384         struct test : no {};
385         template <class TT, class AA>
386         struct test<TT, AA,
387           typename detail::Void< decltype( cereal::access::member_save_minimal( std::declval<AA const &>(), std::declval<TT const &>() ) ) >::type> : yes {};
388         static const bool value = test<T, A>();
389
390         template <class TT, class AA, class SFINAE = void>
391         struct test2 : no {};
392         template <class TT, class AA>
393         struct test2<TT, AA,
394           typename detail::Void< decltype( cereal::access::member_save_minimal_non_const( std::declval<AA const &>(), std::declval<typename std::remove_const<TT>::type&>() ) ) >::type> : yes {};
395         static const bool not_const_type = test2<T, A>();
396         #else // NOT CEREAL_OLDER_GCC =========================================
397         template <class TT, class AA>
398         static auto test(int) -> decltype( cereal::access::member_save_minimal( std::declval<AA const &>(), std::declval<TT const &>() ), yes());
399         template <class, class>
400         static no test(...);
401         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
402
403         template <class TT, class AA>
404         static auto test2(int) -> decltype( cereal::access::member_save_minimal_non_const( std::declval<AA const &>(), std::declval<typename std::remove_const<TT>::type&>() ), yes());
405         template <class, class>
406         static no test2(...);
407         static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value;
408         #endif // NOT CEREAL_OLDER_GCC
409
410         static const bool valid = value || !not_const_type;
411       };
412
413       template <class T, class A, bool Valid>
414       struct get_member_save_minimal_type { typedef void type; };
415
416       template <class T, class A>
417       struct get_member_save_minimal_type<T, A, true>
418       {
419         typedef decltype( cereal::access::member_save_minimal( std::declval<A const &>(), std::declval<T const &>() ) ) type;
420       };
421     } // end namespace detail
422
423     template <class T, class A>
424     struct has_member_save_minimal : std::integral_constant<bool, detail::has_member_save_minimal_impl<T, A>::value>
425     {
426       typedef typename detail::has_member_save_minimal_impl<T, A> check;
427       static_assert( check::valid,
428         "cereal detected a non-const member save_minimal.  "
429         "save_minimal member functions must always be const" );
430
431       typedef typename detail::get_member_save_minimal_type<T, A, check::value>::type type;
432       static_assert( (check::value && is_minimal_type<type>::value) || !check::value,
433         "cereal detected a member save_minimal with an invalid return type.  "
434         "return type must be arithmetic or string" );
435     };
436
437     // ######################################################################
438     // Member Save Minimal (versioned)
439     namespace detail
440     {
441       template <class T, class A>
442       struct has_member_versioned_save_minimal_impl
443       {
444         #ifdef CEREAL_OLDER_GCC
445         template <class TT, class AA, class SFINAE = void>
446         struct test : no {};
447         template <class TT, class AA>
448         struct test<TT, AA,
449           typename detail::Void< decltype( cereal::access::member_save_minimal( std::declval<AA const &>(), std::declval<TT const &>(), 0 ) ) >::type> : yes {};
450         static const bool value = test<T, A>();
451
452         template <class TT, class AA, class SFINAE = void>
453         struct test2 : no {};
454         template <class TT, class AA>
455         struct test2<TT, AA,
456           typename detail::Void< decltype( cereal::access::member_save_minimal_non_const( std::declval<AA const &>(), std::declval<typename std::remove_const<TT>::type&>(), 0 ) ) >::type> : yes {};
457         static const bool not_const_type = test2<T, A>();
458         #else // NOT CEREAL_OLDER_GCC =========================================
459         template <class TT, class AA>
460         static auto test(int) -> decltype( cereal::access::member_save_minimal( std::declval<AA const &>(), std::declval<TT const &>(), 0 ), yes());
461         template <class, class>
462         static no test(...);
463         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
464
465         template <class TT, class AA>
466         static auto test2(int) -> decltype( cereal::access::member_save_minimal_non_const( std::declval<AA const &>(), std::declval<typename std::remove_const<TT>::type&>(), 0 ), yes());
467         template <class, class>
468         static no test2(...);
469         static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value;
470         #endif // NOT_CEREAL_OLDER_GCC
471
472         static const bool valid = value || !not_const_type;
473       };
474
475       template <class T, class A, bool Valid>
476       struct get_member_versioned_save_minimal_type { typedef void type; };
477
478       template <class T, class A>
479       struct get_member_versioned_save_minimal_type<T, A, true>
480       {
481         typedef decltype( cereal::access::member_save_minimal( std::declval<A const &>(), std::declval<T const &>(), 0 ) ) type;
482       };
483     } // end namespace detail
484
485     template <class T, class A>
486     struct has_member_versioned_save_minimal : std::integral_constant<bool, detail::has_member_versioned_save_minimal_impl<T, A>::value>
487     {
488       typedef typename detail::has_member_versioned_save_minimal_impl<T, A> check;
489       static_assert( check::valid,
490         "cereal detected a versioned non-const member save_minimal.  "
491         "save_minimal member functions must always be const" );
492
493       typedef typename detail::get_member_versioned_save_minimal_type<T, A, check::value>::type type;
494       static_assert( (check::value && is_minimal_type<type>::value) || !check::value,
495         "cereal detected a versioned member save_minimal with an invalid return type.  "
496         "return type must be arithmetic or string" );
497     };
498
499     // ######################################################################
500     // Non-Member Save Minimal
501     namespace detail
502     {
503       template <class T, class A>
504       struct has_non_member_save_minimal_impl
505       {
506         template <class TT, class AA>
507         static auto test(int) -> decltype( save_minimal( std::declval<AA const &>(), std::declval<TT const &>() ), yes());
508         template <class, class>
509         static no test(...);
510         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
511
512         template <class TT, class AA>
513         static auto test2(int) -> decltype( save_minimal( std::declval<AA const &>(), std::declval<typename std::remove_const<TT>::type&>() ), yes());
514         template <class, class>
515         static no test2(...);
516         static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value;
517
518         static const bool valid = value || !not_const_type;
519       };
520
521       template <class T, class A, bool Valid>
522       struct get_non_member_save_minimal_type { typedef void type; };
523
524       template <class T, class A>
525       struct get_non_member_save_minimal_type <T, A, true>
526       {
527         typedef decltype( save_minimal( std::declval<A const &>(), std::declval<T const &>() ) ) type;
528       };
529     } // end namespace detail
530
531     template <class T, class A>
532     struct has_non_member_save_minimal : std::integral_constant<bool, detail::has_non_member_save_minimal_impl<T, A>::value>
533     {
534       typedef typename detail::has_non_member_save_minimal_impl<T, A> check;
535       static_assert( check::valid,
536         "cereal detected a non-const type parameter in non-member save_minimal.  "
537         "save_minimal non-member functions must always pass their types as const" );
538
539       typedef typename detail::get_non_member_save_minimal_type<T, A, check::value>::type type;
540       static_assert( (check::value && is_minimal_type<type>::value) || !check::value,
541         "cereal detected a non-member save_minimal with an invalid return type.  "
542         "return type must be arithmetic or string" );
543     };
544
545     // ######################################################################
546     // Non-Member Save Minimal (versioned)
547     namespace detail
548     {
549       template <class T, class A>
550       struct has_non_member_versioned_save_minimal_impl
551       {
552         template <class TT, class AA>
553         static auto test(int) -> decltype( save_minimal( std::declval<AA const &>(), std::declval<TT const &>(), 0 ), yes());
554         template <class, class>
555         static no test(...);
556         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
557
558         template <class TT, class AA>
559         static auto test2(int) -> decltype( save_minimal( std::declval<AA const &>(), std::declval<typename std::remove_const<TT>::type&>(), 0 ), yes());
560         template <class, class>
561         static no test2(...);
562         static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value;
563
564         static const bool valid = value || !not_const_type;
565       };
566
567       template <class T, class A, bool Valid>
568       struct get_non_member_versioned_save_minimal_type { typedef void type; };
569
570       template <class T, class A>
571       struct get_non_member_versioned_save_minimal_type <T, A, true>
572       {
573         typedef decltype( save_minimal( std::declval<A const &>(), std::declval<T const &>(), 0 ) ) type;
574       };
575     } // end namespace detail
576
577     template <class T, class A>
578     struct has_non_member_versioned_save_minimal : std::integral_constant<bool, detail::has_non_member_versioned_save_minimal_impl<T, A>::value>
579     {
580       typedef typename detail::has_non_member_versioned_save_minimal_impl<T, A> check;
581       static_assert( check::valid,
582         "cereal detected a non-const type parameter in versioned non-member save_minimal.  "
583         "save_minimal non-member functions must always pass their types as const" );
584
585       typedef typename detail::get_non_member_versioned_save_minimal_type<T, A, check::value>::type type;
586       static_assert( (check::value && is_minimal_type<type>::value) || !check::value,
587         "cereal detected a non-member versioned save_minimal with an invalid return type.  "
588         "return type must be arithmetic or string" );
589     };
590
591     // ######################################################################
592     // Member Load Minimal
593     namespace detail
594     {
595       //! Used to help strip away conversion wrappers
596       /*! If someone writes a non-member load/save minimal function that accepts its
597           parameter as some generic template type and needs to perform trait checks
598           on that type, our NoConvert wrappers will interfere with this.  Using
599           the struct strip_minmal, users can strip away our wrappers to get to
600           the underlying type, allowing traits to work properly */
601       struct NoConvertBase {};
602
603       //! A struct that prevents implicit conversion
604       /*! Any type instantiated with this struct will be unable to implicitly convert
605           to another type.  Is designed to only allow conversion to Source const &.
606
607           @tparam Source the type of the original source */
608       template <class Source>
609       struct NoConvertConstRef : NoConvertBase
610       {
611         typedef Source type; //!< Used to get underlying type easily
612
613         template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
614         operator Dest () = delete;
615
616         //! only allow conversion if the types are the same and we are converting into a const reference
617         template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
618         operator Dest const & ();
619       };
620
621       //! A struct that prevents implicit conversion
622       /*! Any type instantiated with this struct will be unable to implicitly convert
623           to another type.  Is designed to only allow conversion to Source &.
624
625           @tparam Source the type of the original source */
626       template <class Source>
627       struct NoConvertRef : NoConvertBase
628       {
629         typedef Source type; //!< Used to get underlying type easily
630
631         template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
632         operator Dest () = delete;
633
634         #ifdef __clang__
635         template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
636         operator Dest const & () = delete;
637         #endif // __clang__
638
639         //! only allow conversion if the types are the same and we are converting into a const reference
640         template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
641         operator Dest & ();
642       };
643
644       //! A type that can implicitly convert to anything else
645       struct AnyConvert
646       {
647         template <class Dest>
648         operator Dest & ();
649
650         template <class Dest>
651         operator Dest const & () const;
652       };
653
654       // Our strategy here is to first check if a function matching the signature more or less exists
655       // (allow anything like load_minimal(xxx) using AnyConvert, and then secondly enforce
656       // that it has the correct signature using NoConvertConstRef
657       #ifdef CEREAL_OLDER_GCC
658       template <class T, class A, class SFINAE = void>
659       struct has_member_load_minimal_impl : no {};
660       template <class T, class A>
661       struct has_member_load_minimal_impl<T, A,
662         typename detail::Void<decltype( cereal::access::member_load_minimal( std::declval<A const &>(), std::declval<T&>(), AnyConvert() ) ) >::type> : yes {};
663
664       template <class T, class A, class U, class SFINAE = void>
665       struct has_member_load_minimal_type_impl : no {};
666       template <class T, class A, class U>
667       struct has_member_load_minimal_type_impl<T, A, U,
668         typename detail::Void<decltype( cereal::access::member_load_minimal( std::declval<A const &>(), std::declval<T&>(), NoConvertConstRef<U>() ) ) >::type> : yes {};
669       #else // NOT CEREAL_OLDER_GCC
670       template <class T, class A>
671       struct has_member_load_minimal_impl
672       {
673         template <class TT, class AA>
674         static auto test(int) -> decltype( cereal::access::member_load_minimal( std::declval<AA const &>(), std::declval<TT&>(), AnyConvert() ), yes());
675         template <class, class>
676         static no test(...);
677         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
678       };
679
680       template <class T, class A, class U>
681       struct has_member_load_minimal_type_impl
682       {
683         template <class TT, class AA, class UU>
684         static auto test(int) -> decltype( cereal::access::member_load_minimal( std::declval<AA const &>(), std::declval<TT&>(), NoConvertConstRef<U>() ), yes());
685         template <class, class, class>
686         static no test(...);
687         static const bool value = std::is_same<decltype(test<T, A, U>(0)), yes>::value;
688       };
689       #endif // NOT CEREAL_OLDER_GCC
690
691       template <class T, class A, bool Valid>
692       struct has_member_load_minimal_wrapper : std::false_type {};
693
694       template <class T, class A>
695       struct has_member_load_minimal_wrapper<T, A, true>
696       {
697         static_assert( has_member_save_minimal<T, A>::value,
698           "cereal detected member load_minimal but no valid member save_minimal.  "
699           "cannot evaluate correctness of load_minimal without valid save_minimal." );
700
701         typedef typename detail::get_member_save_minimal_type<T, A, true>::type SaveType;
702         const static bool value = has_member_load_minimal_impl<T, A>::value;
703         const static bool valid = has_member_load_minimal_type_impl<T, A, SaveType>::value;
704
705         static_assert( valid || !value, "cereal detected different or invalid types in corresponding member load_minimal and save_minimal functions.  "
706             "the paramater to load_minimal must be a constant reference to the type that save_minimal returns." );
707       };
708     }
709
710     template <class T, class A>
711     struct has_member_load_minimal : std::integral_constant<bool,
712       detail::has_member_load_minimal_wrapper<T, A, detail::has_member_load_minimal_impl<T, A>::value>::value> {};
713
714     // ######################################################################
715     // Member Load Minimal (versioned)
716     namespace detail
717     {
718       #ifdef CEREAL_OLDER_GCC
719       template <class T, class A, class SFINAE = void>
720       struct has_member_versioned_load_minimal_impl : no {};
721       template <class T, class A>
722       struct has_member_versioned_load_minimal_impl<T, A,
723         typename detail::Void<decltype( cereal::access::member_load_minimal( std::declval<A const &>(), std::declval<T&>(), AnyConvert(), 0 ) ) >::type> : yes {};
724
725       template <class T, class A, class U, class SFINAE = void>
726       struct has_member_versioned_load_minimal_type_impl : no {};
727       template <class T, class A, class U>
728       struct has_member_versioned_load_minimal_type_impl<T, A, U,
729         typename detail::Void<decltype( cereal::access::member_load_minimal( std::declval<A const &>(), std::declval<T&>(), NoConvertConstRef<U>(), 0 ) ) >::type> : yes {};
730       #else // NOT CEREAL_OLDER_GCC
731       template <class T, class A>
732       struct has_member_versioned_load_minimal_impl
733       {
734         template <class TT, class AA>
735         static auto test(int) -> decltype( cereal::access::member_load_minimal( std::declval<AA const &>(), std::declval<TT&>(), AnyConvert(), 0 ), yes());
736         template <class, class>
737         static no test(...);
738         static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
739       };
740
741       template <class T, class A, class U>
742       struct has_member_versioned_load_minimal_type_impl
743       {
744         template <class TT, class AA, class UU>
745         static auto test(int) -> decltype( cereal::access::member_load_minimal( std::declval<AA const &>(), std::declval<TT&>(), NoConvertConstRef<U>(), 0 ), yes());
746         template <class, class, class>
747         static no test(...);
748         static const bool value = std::is_same<decltype(test<T, A, U>(0)), yes>::value;
749       };
750       #endif // NOT CEREAL_OLDER_GCC
751
752       template <class T, class A, bool Valid>
753       struct has_member_versioned_load_minimal_wrapper : std::false_type {};
754
755       template <class T, class A>
756       struct has_member_versioned_load_minimal_wrapper<T, A, true>
757       {
758         static_assert( has_member_versioned_save_minimal<T, A>::value,
759           "cereal detected member versioned load_minimal but no valid member versioned save_minimal.  "
760           "cannot evaluate correctness of load_minimal without valid save_minimal." );
761
762         typedef typename detail::get_member_versioned_save_minimal_type<T, A, true>::type SaveType;
763         const static bool value = has_member_versioned_load_minimal_impl<T, A>::value;
764         const static bool valid = has_member_versioned_load_minimal_type_impl<T, A, SaveType>::value;
765
766         static_assert( valid || !value, "cereal detected different or invalid types in corresponding member versioned load_minimal and save_minimal functions.  "
767             "the paramater to load_minimal must be a constant reference to the type that save_minimal returns." );
768       };
769     }
770
771     template <class T, class A>
772     struct has_member_versioned_load_minimal : std::integral_constant<bool,
773       detail::has_member_versioned_load_minimal_wrapper<T, A, detail::has_member_versioned_load_minimal_impl<T, A>::value>::value> {};
774
775     // ######################################################################
776     // Non-Member Load Minimal
777     namespace detail
778     {
779       #ifdef CEREAL_OLDER_GCC
780       void load_minimal(); // prevents nonsense complaining about not finding this
781       void save_minimal();
782       #endif // CEREAL_OLDER_GCC
783
784       // See notes from member load_minimal
785       template <class T, class A, class U = void>
786       struct has_non_member_load_minimal_impl
787       {
788         template <class TT, class AA>
789         static auto test(int) -> decltype( load_minimal( std::declval<AA const &>(), std::declval<TT&>(), AnyConvert() ), yes() );
790         template <class, class>
791         static no test( ... );
792         static const bool exists = std::is_same<decltype( test<T, A>( 0 ) ), yes>::value;
793
794         template <class TT, class AA, class UU>
795         static auto test2(int) -> decltype( load_minimal( std::declval<AA const &>(), std::declval<TT&>(), NoConvertConstRef<UU>() ), yes() );
796         template <class, class, class>
797         static no test2( ... );
798         static const bool valid = std::is_same<decltype( test2<T, A, U>( 0 ) ), yes>::value;
799
800         template <class TT, class AA>
801         static auto test3(int) -> decltype( load_minimal( std::declval<AA const &>(), NoConvertRef<TT>(), AnyConvert() ), yes() );
802         template <class, class>
803         static no test3( ... );
804         static const bool const_valid = std::is_same<decltype( test3<T, A>( 0 ) ), yes>::value;
805       };
806
807       template <class T, class A, bool Valid>
808       struct has_non_member_load_minimal_wrapper : std::false_type {};
809
810       template <class T, class A>
811       struct has_non_member_load_minimal_wrapper<T, A, true>
812       {
813         static_assert( detail::has_non_member_save_minimal_impl<T, A>::valid,
814           "cereal detected non-member load_minimal but no valid non-member save_minimal.  "
815           "cannot evaluate correctness of load_minimal without valid save_minimal." );
816
817         typedef typename detail::get_non_member_save_minimal_type<T, A, true>::type SaveType;
818         typedef has_non_member_load_minimal_impl<T, A, SaveType> check;
819         static const bool value = check::exists;
820
821         static_assert( check::valid || !check::exists, "cereal detected different types in corresponding non-member load_minimal and save_minimal functions.  "
822             "the paramater to load_minimal must be a constant reference to the type that save_minimal returns." );
823         static_assert( check::const_valid || !check::exists, "cereal detected an invalid serialization type parameter in non-member load_minimal.  "
824             "load_minimal non-member functions must accept their serialization type by non-const reference" );
825       };
826     }
827
828     template <class T, class A>
829     struct has_non_member_load_minimal : std::integral_constant<bool,
830       detail::has_non_member_load_minimal_wrapper<T, A, detail::has_non_member_load_minimal_impl<T, A>::exists>::value> {};
831
832     // ######################################################################
833     // Non-Member Load Minimal (versioned)
834     namespace detail
835     {
836       // See notes from member load_minimal
837       template <class T, class A, class U = void>
838       struct has_non_member_versioned_load_minimal_impl
839       {
840         template <class TT, class AA>
841         static auto test(int) -> decltype( load_minimal( std::declval<AA const &>(), std::declval<TT&>(), AnyConvert(), 0 ), yes() );
842         template <class, class>
843         static no test( ... );
844         static const bool exists = std::is_same<decltype( test<T, A>( 0 ) ), yes>::value;
845
846         template <class TT, class AA, class UU>
847         static auto test2(int) -> decltype( load_minimal( std::declval<AA const &>(), std::declval<TT&>(), NoConvertConstRef<UU>(), 0 ), yes() );
848         template <class, class, class>
849         static no test2( ... );
850         static const bool valid = std::is_same<decltype( test2<T, A, U>( 0 ) ), yes>::value;
851
852         template <class TT, class AA>
853         static auto test3(int) -> decltype( load_minimal( std::declval<AA const &>(), NoConvertRef<TT>(), AnyConvert(), 0 ), yes() );
854         template <class, class>
855         static no test3( ... );
856         static const bool const_valid = std::is_same<decltype( test3<T, A>( 0 ) ), yes>::value;
857       };
858
859       template <class T, class A, bool Valid>
860       struct has_non_member_versioned_load_minimal_wrapper : std::false_type {};
861
862       template <class T, class A>
863       struct has_non_member_versioned_load_minimal_wrapper<T, A, true>
864       {
865         static_assert( detail::has_non_member_versioned_save_minimal_impl<T, A>::valid,
866           "cereal detected non-member versioned load_minimal but no valid non-member versioned save_minimal.  "
867           "cannot evaluate correctness of load_minimal without valid save_minimal." );
868
869         typedef typename detail::get_non_member_versioned_save_minimal_type<T, A, true>::type SaveType;
870         typedef has_non_member_versioned_load_minimal_impl<T, A, SaveType> check;;
871         static const bool value = check::exists;
872
873         static_assert( check::valid || !check::exists, "cereal detected different types in corresponding non-member versioned load_minimal and save_minimal functions.  "
874             "the paramater to load_minimal must be a constant reference to the type that save_minimal returns." );
875         static_assert( check::const_valid || !check::exists, "cereal detected an invalid serialization type parameter in non-member versioned load_minimal.  "
876             "load_minimal non-member versioned functions must accept their serialization type by non-const reference" );
877       };
878     }
879
880     template <class T, class A>
881     struct has_non_member_versioned_load_minimal : std::integral_constant<bool,
882       detail::has_non_member_versioned_load_minimal_wrapper<T, A, detail::has_non_member_versioned_load_minimal_impl<T, A>::exists>::value> {};
883
884     // ######################################################################
885     template <class T, class InputArchive, class OutputArchive>
886     struct has_member_split : std::integral_constant<bool,
887       (has_member_load<T, InputArchive>::value && has_member_save<T, OutputArchive>::value) ||
888       (has_member_versioned_load<T, InputArchive>::value && has_member_versioned_save<T, OutputArchive>::value)> {};
889
890     // ######################################################################
891     template <class T, class InputArchive, class OutputArchive>
892     struct has_non_member_split : std::integral_constant<bool,
893       (has_non_member_load<T, InputArchive>::value && has_non_member_save<T, OutputArchive>::value) ||
894       (has_non_member_versioned_load<T, InputArchive>::value && has_non_member_versioned_save<T, OutputArchive>::value)> {};
895
896     // ######################################################################
897     template <class T, class OutputArchive>
898     struct is_output_serializable : std::integral_constant<bool,
899       has_member_save<T, OutputArchive>::value +
900       has_non_member_save<T, OutputArchive>::value +
901       has_member_serialize<T, OutputArchive>::value +
902       has_non_member_serialize<T, OutputArchive>::value +
903       has_member_save_minimal<T, OutputArchive>::value +
904       has_non_member_save_minimal<T, OutputArchive>::value +
905       /*-versioned---------------------------------------------------------*/
906       has_member_versioned_save<T, OutputArchive>::value +
907       has_non_member_versioned_save<T, OutputArchive>::value +
908       has_member_versioned_serialize<T, OutputArchive>::value +
909       has_non_member_versioned_serialize<T, OutputArchive>::value +
910       has_member_versioned_save_minimal<T, OutputArchive>::value +
911       has_non_member_versioned_save_minimal<T, OutputArchive>::value == 1> {};
912
913     // ######################################################################
914     template <class T, class InputArchive>
915     struct is_input_serializable : std::integral_constant<bool,
916       has_member_load<T, InputArchive>::value +
917       has_non_member_load<T, InputArchive>::value +
918       has_member_serialize<T, InputArchive>::value +
919       has_non_member_serialize<T, InputArchive>::value +
920       has_member_load_minimal<T, InputArchive>::value +
921       has_non_member_load_minimal<T, InputArchive>::value +
922       /*-versioned---------------------------------------------------------*/
923       has_member_versioned_load<T, InputArchive>::value +
924       has_non_member_versioned_load<T, InputArchive>::value +
925       has_member_versioned_serialize<T, InputArchive>::value +
926       has_non_member_versioned_serialize<T, InputArchive>::value +
927       has_member_versioned_load_minimal<T, InputArchive>::value +
928       has_non_member_versioned_load_minimal<T, InputArchive>::value == 1> {};
929
930     // ######################################################################
931     template <class T, class OutputArchive>
932     struct has_invalid_output_versioning : std::integral_constant<bool,
933       (has_member_versioned_save<T, OutputArchive>::value && has_member_save<T, OutputArchive>::value) ||
934       (has_non_member_versioned_save<T, OutputArchive>::value && has_non_member_save<T, OutputArchive>::value) ||
935       (has_member_versioned_serialize<T, OutputArchive>::value && has_member_serialize<T, OutputArchive>::value) ||
936       (has_non_member_versioned_serialize<T, OutputArchive>::value && has_non_member_serialize<T, OutputArchive>::value) ||
937       (has_member_versioned_save_minimal<T, OutputArchive>::value && has_member_save_minimal<T, OutputArchive>::value) ||
938       (has_non_member_versioned_save_minimal<T, OutputArchive>::value &&  has_non_member_save_minimal<T, OutputArchive>::value)> {};
939
940     // ######################################################################
941     template <class T, class InputArchive>
942     struct has_invalid_input_versioning : std::integral_constant<bool,
943       (has_member_versioned_load<T, InputArchive>::value && has_member_load<T, InputArchive>::value) ||
944       (has_non_member_versioned_load<T, InputArchive>::value && has_non_member_load<T, InputArchive>::value) ||
945       (has_member_versioned_serialize<T, InputArchive>::value && has_member_serialize<T, InputArchive>::value) ||
946       (has_non_member_versioned_serialize<T, InputArchive>::value && has_non_member_serialize<T, InputArchive>::value) ||
947       (has_member_versioned_load_minimal<T, InputArchive>::value && has_member_load_minimal<T, InputArchive>::value) ||
948       (has_non_member_versioned_load_minimal<T, InputArchive>::value &&  has_non_member_load_minimal<T, InputArchive>::value)> {};
949
950     // ######################################################################
951     namespace detail
952     {
953       template <class T, class A>
954       struct is_specialized_member_serialize : std::integral_constant<bool,
955         !std::is_base_of<std::false_type, specialize<A, T, specialization::member_serialize>>::value> {};
956
957       template <class T, class A>
958       struct is_specialized_member_load_save : std::integral_constant<bool,
959         !std::is_base_of<std::false_type, specialize<A, T, specialization::member_load_save>>::value> {};
960
961       template <class T, class A>
962       struct is_specialized_member_load_save_minimal : std::integral_constant<bool,
963         !std::is_base_of<std::false_type, specialize<A, T, specialization::member_load_save_minimal>>::value> {};
964
965       template <class T, class A>
966       struct is_specialized_non_member_serialize : std::integral_constant<bool,
967         !std::is_base_of<std::false_type, specialize<A, T, specialization::non_member_serialize>>::value> {};
968
969       template <class T, class A>
970       struct is_specialized_non_member_load_save : std::integral_constant<bool,
971         !std::is_base_of<std::false_type, specialize<A, T, specialization::non_member_load_save>>::value> {};
972
973       template <class T, class A>
974       struct is_specialized_non_member_load_save_minimal : std::integral_constant<bool,
975         !std::is_base_of<std::false_type, specialize<A, T, specialization::non_member_load_save_minimal>>::value> {};
976
977       // Considered an error if specialization exists for more than one type
978       template <class T, class A>
979       struct is_specialized_error : std::integral_constant<bool,
980         (is_specialized_member_serialize<T, A>::value +
981          is_specialized_member_load_save<T, A>::value +
982          is_specialized_member_load_save_minimal<T, A>::value +
983          is_specialized_non_member_serialize<T, A>::value +
984          is_specialized_non_member_load_save<T, A>::value +
985          is_specialized_non_member_load_save_minimal<T, A>::value) <= 1> {};
986     } // namespace detail
987
988     template <class T, class A>
989     struct is_specialized : std::integral_constant<bool,
990       detail::is_specialized_member_serialize<T, A>::value ||
991       detail::is_specialized_member_load_save<T, A>::value ||
992       detail::is_specialized_member_load_save_minimal<T, A>::value ||
993       detail::is_specialized_non_member_serialize<T, A>::value ||
994       detail::is_specialized_non_member_load_save<T, A>::value ||
995       detail::is_specialized_non_member_load_save_minimal<T, A>::value>
996     {
997       static_assert(detail::is_specialized_error<T, A>::value, "More than one explicit specialization detected for type.");
998     };
999
1000     template <class T, class A>
1001     struct is_specialized_member_serialize : std::integral_constant<bool,
1002       is_specialized<T, A>::value && detail::is_specialized_member_serialize<T, A>::value>
1003     {
1004       static_assert( (is_specialized<T, A>::value && detail::is_specialized_member_serialize<T, A>::value &&
1005                      (has_member_serialize<T, A>::value || has_member_versioned_serialize<T, A>::value))
1006                      || !(is_specialized<T, A>::value && detail::is_specialized_member_serialize<T, A>::value),
1007                      "cereal detected member serialization specialization but no member serialize function" );
1008     };
1009
1010     template <class T, class A>
1011     struct is_specialized_member_load : std::integral_constant<bool,
1012       is_specialized<T, A>::value && detail::is_specialized_member_load_save<T, A>::value>
1013     {
1014       static_assert( (is_specialized<T, A>::value && detail::is_specialized_member_load_save<T, A>::value &&
1015                      (has_member_load<T, A>::value || has_member_versioned_load<T, A>::value))
1016                      || !(is_specialized<T, A>::value && detail::is_specialized_member_load_save<T, A>::value),
1017                      "cereal detected member load specialization but no member load function" );
1018     };
1019
1020     template <class T, class A>
1021     struct is_specialized_member_save : std::integral_constant<bool,
1022       is_specialized<T, A>::value && detail::is_specialized_member_load_save<T, A>::value>
1023     {
1024       static_assert( (is_specialized<T, A>::value && detail::is_specialized_member_load_save<T, A>::value &&
1025                      (has_member_save<T, A>::value || has_member_versioned_save<T, A>::value))
1026                      || !(is_specialized<T, A>::value && detail::is_specialized_member_load_save<T, A>::value),
1027                      "cereal detected member save specialization but no member save function" );
1028     };
1029
1030     template <class T, class A>
1031     struct is_specialized_member_load_minimal : std::integral_constant<bool,
1032       is_specialized<T, A>::value && detail::is_specialized_member_load_save_minimal<T, A>::value>
1033     {
1034       static_assert( (is_specialized<T, A>::value && detail::is_specialized_member_load_save_minimal<T, A>::value &&
1035                      (has_member_load_minimal<T, A>::value || has_member_versioned_load_minimal<T, A>::value))
1036                      || !(is_specialized<T, A>::value && detail::is_specialized_member_load_save_minimal<T, A>::value),
1037                      "cereal detected member load_minimal specialization but no member load_minimal function" );
1038     };
1039
1040     template <class T, class A>
1041     struct is_specialized_member_save_minimal : std::integral_constant<bool,
1042       is_specialized<T, A>::value && detail::is_specialized_member_load_save_minimal<T, A>::value>
1043     {
1044       static_assert( (is_specialized<T, A>::value && detail::is_specialized_member_load_save_minimal<T, A>::value &&
1045                      (has_member_save_minimal<T, A>::value || has_member_versioned_save_minimal<T, A>::value))
1046                      || !(is_specialized<T, A>::value && detail::is_specialized_member_load_save_minimal<T, A>::value),
1047                      "cereal detected member save_minimal specialization but no member save_minimal function" );
1048     };
1049
1050     template <class T, class A>
1051     struct is_specialized_non_member_serialize : std::integral_constant<bool,
1052       is_specialized<T, A>::value && detail::is_specialized_non_member_serialize<T, A>::value>
1053     {
1054       static_assert( (is_specialized<T, A>::value && detail::is_specialized_non_member_serialize<T, A>::value &&
1055                      (has_non_member_serialize<T, A>::value || has_non_member_versioned_serialize<T, A>::value))
1056                      || !(is_specialized<T, A>::value && detail::is_specialized_non_member_serialize<T, A>::value),
1057                      "cereal detected non-member serialization specialization but no non-member serialize function" );
1058     };
1059
1060     template <class T, class A>
1061     struct is_specialized_non_member_load : std::integral_constant<bool,
1062       is_specialized<T, A>::value && detail::is_specialized_non_member_load_save<T, A>::value>
1063     {
1064       static_assert( (is_specialized<T, A>::value && detail::is_specialized_non_member_load_save<T, A>::value &&
1065                      (has_non_member_load<T, A>::value || has_non_member_versioned_load<T, A>::value))
1066                      || !(is_specialized<T, A>::value && detail::is_specialized_non_member_load_save<T, A>::value),
1067                      "cereal detected non-member load specialization but no non-member load function" );
1068     };
1069
1070     template <class T, class A>
1071     struct is_specialized_non_member_save : std::integral_constant<bool,
1072       is_specialized<T, A>::value && detail::is_specialized_non_member_load_save<T, A>::value>
1073     {
1074       static_assert( (is_specialized<T, A>::value && detail::is_specialized_non_member_load_save<T, A>::value &&
1075                      (has_non_member_save<T, A>::value || has_non_member_versioned_save<T, A>::value))
1076                      || !(is_specialized<T, A>::value && detail::is_specialized_non_member_load_save<T, A>::value),
1077                      "cereal detected non-member save specialization but no non-member save function" );
1078     };
1079
1080     template <class T, class A>
1081     struct is_specialized_non_member_load_minimal : std::integral_constant<bool,
1082       is_specialized<T, A>::value && detail::is_specialized_non_member_load_save_minimal<T, A>::value>
1083     {
1084       static_assert( (is_specialized<T, A>::value && detail::is_specialized_non_member_load_save_minimal<T, A>::value &&
1085                      (has_non_member_load_minimal<T, A>::value || has_non_member_versioned_load_minimal<T, A>::value))
1086                      || !(is_specialized<T, A>::value && detail::is_specialized_non_member_load_save_minimal<T, A>::value),
1087                      "cereal detected non-member load specialization but no non-member load function" );
1088     };
1089
1090     template <class T, class A>
1091     struct is_specialized_non_member_save_minimal : std::integral_constant<bool,
1092       is_specialized<T, A>::value && detail::is_specialized_non_member_load_save_minimal<T, A>::value>
1093     {
1094       static_assert( (is_specialized<T, A>::value && detail::is_specialized_non_member_load_save_minimal<T, A>::value &&
1095                      (has_non_member_save_minimal<T, A>::value || has_non_member_versioned_save_minimal<T, A>::value))
1096                      || !(is_specialized<T, A>::value && detail::is_specialized_non_member_load_save_minimal<T, A>::value),
1097                      "cereal detected non-member save specialization but no non-member save function" );
1098     };
1099
1100     // ######################################################################
1101     // detects if a type has any active minimal output serialization
1102     template <class T, class OutputArchive>
1103     struct has_minimal_output_serialization : std::integral_constant<bool,
1104       is_specialized_member_save_minimal<T, OutputArchive>::value ||
1105       ((has_member_save_minimal<T, OutputArchive>::value ||
1106         has_non_member_save_minimal<T, OutputArchive>::value ||
1107         has_member_versioned_save_minimal<T, OutputArchive>::value ||
1108         has_non_member_versioned_save_minimal<T, OutputArchive>::value) &&
1109        (!is_specialized_member_serialize<T, OutputArchive>::value ||
1110         !is_specialized_member_save<T, OutputArchive>::value))> {};
1111
1112     // ######################################################################
1113     // detects if a type has any active minimal input serialization
1114     template <class T, class InputArchive>
1115     struct has_minimal_input_serialization : std::integral_constant<bool,
1116       is_specialized_member_load_minimal<T, InputArchive>::value ||
1117       ((has_member_load_minimal<T, InputArchive>::value ||
1118         has_non_member_load_minimal<T, InputArchive>::value ||
1119         has_member_versioned_load_minimal<T, InputArchive>::value ||
1120         has_non_member_versioned_load_minimal<T, InputArchive>::value) &&
1121        (!is_specialized_member_serialize<T, InputArchive>::value ||
1122         !is_specialized_member_load<T, InputArchive>::value))> {};
1123
1124     // ######################################################################
1125     namespace detail
1126     {
1127       struct base_class_id
1128       {
1129         template<class T>
1130           base_class_id(T const * const t) :
1131           type(typeid(T)),
1132           ptr(t),
1133           hash(std::hash<std::type_index>()(typeid(T)) ^ (std::hash<void const *>()(t) << 1))
1134           { }
1135
1136           bool operator==(base_class_id const & other) const
1137           { return (type == other.type) && (ptr == other.ptr); }
1138
1139           std::type_index type;
1140           void const * ptr;
1141           size_t hash;
1142       };
1143       struct base_class_id_hash { size_t operator()(base_class_id const & id) const { return id.hash; }  };
1144     } // namespace detail
1145
1146     // ######################################################################
1147     //! A macro to use to restrict which types of archives your function will work for.
1148     /*! This requires you to have a template class parameter named Archive and replaces the void return
1149         type for your function.
1150
1151         INTYPE refers to the input archive type you wish to restrict on.
1152         OUTTYPE refers to the output archive type you wish to restrict on.
1153
1154         For example, if we want to limit a serialize to only work with binary serialization:
1155
1156         @code{.cpp}
1157         template <class Archive>
1158         CEREAL_ARCHIVE_RESTRICT(BinaryInputArchive, BinaryOutputArchive)
1159         serialize( Archive & ar, MyCoolType & m )
1160         {
1161           ar & m;
1162         }
1163         @endcode
1164
1165         If you need to do more restrictions in your enable_if, you will need to do this by hand.
1166      */
1167     #define CEREAL_ARCHIVE_RESTRICT(INTYPE, OUTTYPE) \
1168     typename std::enable_if<std::is_same<Archive, INTYPE>::value || std::is_same<Archive, OUTTYPE>::value, void>::type
1169
1170     // ######################################################################
1171     namespace detail
1172     {
1173       struct shared_from_this_wrapper
1174       {
1175         template <class U>
1176         static auto check( U const & t ) -> decltype( ::cereal::access::shared_from_this(t), std::true_type() );
1177
1178         static auto check( ... ) -> decltype( std::false_type() );
1179
1180         template <class U>
1181         static auto get( U const & t ) -> decltype( t.shared_from_this() );
1182       };
1183     }
1184
1185     // works around the lack of decltype inheritance in GCC 4.6
1186     template<class T>
1187     struct shared_wrapper
1188     {
1189        typedef decltype(detail::shared_from_this_wrapper::check(std::declval<T>())) type;
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 : shared_wrapper<T>::type
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         typedef decltype(detail::shared_from_this_wrapper::get(std::declval<T>())) PtrType;
1203       public:
1204         //! The type of the base of T that inherited from std::enable_shared_from_this
1205         typedef typename std::decay<typename PtrType::element_type>::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       typedef T type;
1220     };
1221
1222     //! Specialization for types wrapped in a NoConvert
1223     template <class T>
1224     struct strip_minimal<T, true>
1225     {
1226       typedef typename T::type type;
1227     };
1228   } // namespace traits
1229
1230   // ######################################################################
1231   namespace detail
1232   {
1233     template <class T, class A, bool Member = traits::has_member_load_and_construct<T, A>::value, bool NonMember = traits::has_non_member_load_and_construct<T, A>::value>
1234     struct Construct
1235     {
1236       static_assert( cereal::traits::detail::delay_static_assert<T>::value,
1237         "Cereal detected both member and non member load_and_construct functions!" );
1238       static T * load_andor_construct( A & /*ar*/, construct<T> & /*construct*/ )
1239       { return nullptr; }
1240     };
1241
1242     template<class T>
1243     struct is_default_constructible : std::is_constructible<T>{};
1244     template <class T, class A>
1245     struct Construct<T, A, false, false>
1246     {
1247       static_assert( is_default_constructible<T>::value,
1248                      "Trying to serialize a an object with no default constructor. \n\n "
1249                      "Types must either be default constructible or define either a member or non member Construct function. \n "
1250                      "Construct functions generally have the signature: \n\n "
1251                      "template <class Archive> \n "
1252                      "static void load_and_construct(Archive & ar, cereal::construct<T> & construct) \n "
1253                      "{ \n "
1254                      "  var a; \n "
1255                      "  ar( a ) \n "
1256                      "  construct( a ); \n "
1257                      "} \n\n" );
1258       static T * load_andor_construct()
1259       { return new T(); }
1260     };
1261
1262     template <class T, class A>
1263     struct Construct<T, A, true, false>
1264     {
1265       static void load_andor_construct( A & ar, construct<T> & construct )
1266       {
1267         access::load_and_construct<T>( ar, construct );
1268       }
1269     };
1270
1271     template <class T, class A>
1272     struct Construct<T, A, false, true>
1273     {
1274       static void load_andor_construct( A & ar, construct<T> & construct )
1275       {
1276         LoadAndConstruct<T>::load_and_construct( ar, construct );
1277       }
1278     };
1279   } // namespace detail
1280 } // namespace cereal
1281
1282 #endif // CEREAL_DETAILS_TRAITS_HPP_