cereal
A C++11 library for serialization
traits.hpp
Go to the documentation of this file.
1 
4 /*
5  Copyright (c) 2014, Randolph Voorhies, Shane Grant
6  All rights reserved.
7 
8  Redistribution and use in source and binary forms, with or without
9  modification, are permitted provided that the following conditions are met:
10  * Redistributions of source code must retain the above copyright
11  notice, this list of conditions and the following disclaimer.
12  * Redistributions in binary form must reproduce the above copyright
13  notice, this list of conditions and the following disclaimer in the
14  documentation and/or other materials provided with the distribution.
15  * Neither the name of the copyright holder nor the
16  names of its contributors may be used to endorse or promote products
17  derived from this software without specific prior written permission.
18 
19  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
23  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #ifndef CEREAL_DETAILS_TRAITS_HPP_
31 #define CEREAL_DETAILS_TRAITS_HPP_
32 
33 #ifndef __clang__
34 #if (__GNUC__ == 4 && __GNUC_MINOR__ <= 7)
35 #define CEREAL_OLDER_GCC
36 #endif // gcc 4.7 or earlier
37 #endif // __clang__
38 
39 #include <type_traits>
40 #include <typeindex>
41 
42 #include "cereal/macros.hpp"
43 #include "cereal/access.hpp"
44 
45 namespace cereal
46 {
47  namespace traits
48  {
49  using yes = std::true_type;
50  using no = std::false_type;
51 
52  namespace detail
53  {
54  // ######################################################################
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 
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 
86 
88  static const detail::sfinae sfinae = {};
89 
90  // ######################################################################
92 
115  template <bool ... Conditions>
116  using EnableIf = typename detail::EnableIfHelper<Conditions...>::type;
117 
118  // ######################################################################
120 
147  template <bool ... Conditions>
148  using DisableIf = typename detail::DisableIfHelper<Conditions...>::type;
149 
150  // ######################################################################
151  namespace detail
152  {
153  template <class InputArchive>
155  {
157  "Could not find an associated output archive for input archive." );
158  };
159 
160  template <class OutputArchive>
162  {
164  "Could not find an associated input archive for output archive." );
165  };
166  }
167 
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  // ######################################################################
178  #define CEREAL_MAKE_VERSIONED_TEST ,0
179 
180  // ######################################################################
182 
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  // ######################################################################
215 
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
244 
245  // ######################################################################
246  // Non Member Serialize (versioned)
248 
249  // ######################################################################
250  // Member Load
251  CEREAL_MAKE_HAS_MEMBER_TEST(load, load,);
252 
253  // ######################################################################
254  // Member Load (versioned)
256 
257  // ######################################################################
258  // Non Member Load
260 
261  // ######################################################################
262  // Non Member Load (versioned)
264 
265  // ######################################################################
266  #undef CEREAL_MAKE_HAS_NON_MEMBER_TEST
267  #undef CEREAL_MAKE_HAS_MEMBER_TEST
268 
269  // ######################################################################
271 
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
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)
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  // ######################################################################
353 
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
392 
393  // ######################################################################
394  // Non Member Save (versioned)
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  // ######################################################################
418 
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  // ######################################################################
476 
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  // ######################################################################
498 
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
522 
523  // ######################################################################
524  // Member Save Minimal (versioned)
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  // ######################################################################
536 
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
592 
593  // ######################################################################
594  // Non-Member Save Minimal (versioned)
596 
597  // ######################################################################
598  #undef CEREAL_MAKE_HAS_NON_MEMBER_SAVE_MINIMAL_TEST
599 
600  // ######################################################################
601  // Load Minimal Utilities
602  namespace detail
603  {
605 
610  struct NoConvertBase {};
611 
613 
617  template <class Source>
619  {
620  using type = Source;
621 
622  template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
623  operator Dest () = delete;
624 
626  template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
627  operator Dest const & ();
628  };
629 
631 
635  template <class Source>
637  {
638  using type = Source;
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 
649  template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
650  operator Dest & ();
651  };
652 
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  // ######################################################################
666 
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  // ######################################################################
721 
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  // ######################################################################
759 
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
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)
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
793  #endif // CEREAL_OLDER_GCC
794  } // namespace detail
795 
796  // ######################################################################
798 
818  #define CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST(test_name, save_name, versioned) \
819  namespace detail \
820  { \
821  template <class T, class A, class U = void> \
822  struct has_non_member_##test_name##_impl \
823  { \
824  template <class TT, class AA> \
825  static auto test(int) -> decltype( CEREAL_LOAD_MINIMAL_FUNCTION_NAME( \
826  std::declval<AA const &>(), std::declval<TT&>(), AnyConvert() versioned ), yes() ); \
827  template <class, class> static no test( ... ); \
828  static const bool exists = std::is_same<decltype( test<T, A>( 0 ) ), yes>::value; \
829  \
830  template <class TT, class AA, class UU> \
831  static auto test2(int) -> decltype( CEREAL_LOAD_MINIMAL_FUNCTION_NAME( \
832  std::declval<AA const &>(), std::declval<TT&>(), NoConvertConstRef<UU>() versioned ), yes() ); \
833  template <class, class, class> static no test2( ... ); \
834  static const bool valid = std::is_same<decltype( test2<T, A, U>( 0 ) ), yes>::value; \
835  \
836  template <class TT, class AA> \
837  static auto test3(int) -> decltype( CEREAL_LOAD_MINIMAL_FUNCTION_NAME( \
838  std::declval<AA const &>(), NoConvertRef<TT>(), AnyConvert() versioned ), yes() ); \
839  template <class, class> static no test3( ... ); \
840  static const bool const_valid = std::is_same<decltype( test3<T, A>( 0 ) ), yes>::value; \
841  }; \
842  \
843  template <class T, class A, bool Valid> \
844  struct has_non_member_##test_name##_wrapper : std::false_type {}; \
845  \
846  template <class T, class A> \
847  struct has_non_member_##test_name##_wrapper<T, A, true> \
848  { \
849  using AOut = typename detail::get_output_from_input<A>::type; \
850  \
851  static_assert( detail::has_non_member_##save_name##_impl<T, AOut>::valid, \
852  "cereal detected non-member " #test_name " but no valid non-member " #save_name ". \n " \
853  "cannot evaluate correctness of " #test_name " without valid " #save_name "." ); \
854  \
855  using SaveType = typename detail::get_non_member_##save_name##_type<T, AOut, true>::type; \
856  using check = has_non_member_##test_name##_impl<T, A, SaveType>; \
857  static const bool value = check::exists; \
858  \
859  static_assert( check::valid || !check::exists, "cereal detected different types in corresponding non-member " \
860  #test_name " and " #save_name " functions. \n " \
861  "the paramater to " #test_name " must be a constant reference to the type that " #save_name " returns." ); \
862  }; \
863  } /* namespace detail */ \
864  \
865  template <class T, class A> \
866  struct has_non_member_##test_name : std::integral_constant<bool, \
867  detail::has_non_member_##test_name##_wrapper<T, A, detail::has_non_member_##test_name##_impl<T, A>::exists>::value> {};
868 
869  // ######################################################################
870  // Non-Member Load Minimal
871  CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST(load_minimal, save_minimal, )
872 
873  // ######################################################################
874  // Non-Member Load Minimal (versioned)
875  CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST(versioned_load_minimal, versioned_save_minimal, CEREAL_MAKE_VERSIONED_TEST)
876 
877  // ######################################################################
878  #undef CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST
879 
880  // ######################################################################
881  namespace detail
882  {
883  // const stripped away before reaching here, prevents errors on conversion from
884  // construct<const T> to construct<T>
885  template<typename T, typename A>
886  struct has_member_load_and_construct_impl : std::integral_constant<bool,
887  std::is_same<decltype( access::load_and_construct<T>( std::declval<A&>(), std::declval< ::cereal::construct<T>&>() ) ), void>::value>
888  { };
889 
890  template<typename T, typename A>
891  struct has_member_versioned_load_and_construct_impl : std::integral_constant<bool,
892  std::is_same<decltype( access::load_and_construct<T>( std::declval<A&>(), std::declval< ::cereal::construct<T>&>(), 0 ) ), void>::value>
893  { };
894  } // namespace detail
895 
897  template<typename T, typename A>
898  struct has_member_load_and_construct : detail::has_member_load_and_construct_impl<typename std::remove_const<T>::type, A>
899  { };
900 
902  template<typename T, typename A>
904  { };
905 
906  // ######################################################################
908 
910  #define CEREAL_MAKE_HAS_NON_MEMBER_LOAD_AND_CONSTRUCT_TEST(test_name, versioned) \
911  namespace detail \
912  { \
913  template <class T, class A> \
914  struct has_non_member_##test_name##_impl \
915  { \
916  template <class TT, class AA> \
917  static auto test(int) -> decltype( LoadAndConstruct<TT>::load_and_construct( \
918  std::declval<AA&>(), std::declval< ::cereal::construct<TT>&>() versioned ), yes()); \
919  template <class, class> \
920  static no test( ... ); \
921  static const bool value = std::is_same<decltype( test<T, A>( 0 ) ), yes>::value; \
922  }; \
923  } /* end namespace detail */ \
924  template <class T, class A> \
925  struct has_non_member_##test_name : \
926  std::integral_constant<bool, detail::has_non_member_##test_name##_impl<typename std::remove_const<T>::type, A>::value> {};
927 
928  // ######################################################################
931 
932  // ######################################################################
935 
936  // ######################################################################
938  template<typename T, typename A>
939  struct has_load_and_construct : std::integral_constant<bool,
940  has_member_load_and_construct<T, A>::value || has_non_member_load_and_construct<T, A>::value ||
941  has_member_versioned_load_and_construct<T, A>::value || has_non_member_versioned_load_and_construct<T, A>::value>
942  { };
943 
944  // ######################################################################
945  #undef CEREAL_MAKE_HAS_NON_MEMBER_LOAD_AND_CONSTRUCT_TEST
946 
947  // ######################################################################
948  // End of serialization existence tests
949  #undef CEREAL_MAKE_VERSIONED_TEST
950 
951  // ######################################################################
952  template <class T, class InputArchive, class OutputArchive>
953  struct has_member_split : std::integral_constant<bool,
954  (has_member_load<T, InputArchive>::value && has_member_save<T, OutputArchive>::value) ||
955  (has_member_versioned_load<T, InputArchive>::value && has_member_versioned_save<T, OutputArchive>::value)> {};
956 
957  // ######################################################################
958  template <class T, class InputArchive, class OutputArchive>
959  struct has_non_member_split : std::integral_constant<bool,
960  (has_non_member_load<T, InputArchive>::value && has_non_member_save<T, OutputArchive>::value) ||
961  (has_non_member_versioned_load<T, InputArchive>::value && has_non_member_versioned_save<T, OutputArchive>::value)> {};
962 
963  // ######################################################################
964  template <class T, class OutputArchive>
965  struct has_invalid_output_versioning : std::integral_constant<bool,
966  (has_member_versioned_save<T, OutputArchive>::value && has_member_save<T, OutputArchive>::value) ||
967  (has_non_member_versioned_save<T, OutputArchive>::value && has_non_member_save<T, OutputArchive>::value) ||
968  (has_member_versioned_serialize<T, OutputArchive>::value && has_member_serialize<T, OutputArchive>::value) ||
969  (has_non_member_versioned_serialize<T, OutputArchive>::value && has_non_member_serialize<T, OutputArchive>::value) ||
970  (has_member_versioned_save_minimal<T, OutputArchive>::value && has_member_save_minimal<T, OutputArchive>::value) ||
971  (has_non_member_versioned_save_minimal<T, OutputArchive>::value && has_non_member_save_minimal<T, OutputArchive>::value)> {};
972 
973  // ######################################################################
974  template <class T, class InputArchive>
975  struct has_invalid_input_versioning : std::integral_constant<bool,
976  (has_member_versioned_load<T, InputArchive>::value && has_member_load<T, InputArchive>::value) ||
977  (has_non_member_versioned_load<T, InputArchive>::value && has_non_member_load<T, InputArchive>::value) ||
978  (has_member_versioned_serialize<T, InputArchive>::value && has_member_serialize<T, InputArchive>::value) ||
979  (has_non_member_versioned_serialize<T, InputArchive>::value && has_non_member_serialize<T, InputArchive>::value) ||
980  (has_member_versioned_load_minimal<T, InputArchive>::value && has_member_load_minimal<T, InputArchive>::value) ||
981  (has_non_member_versioned_load_minimal<T, InputArchive>::value && has_non_member_load_minimal<T, InputArchive>::value)> {};
982 
983  // ######################################################################
984  namespace detail
985  {
987  #define CEREAL_MAKE_IS_SPECIALIZED_IMPL(name) \
988  template <class T, class A> \
989  struct is_specialized_##name : std::integral_constant<bool, \
990  !std::is_base_of<std::false_type, specialize<A, T, specialization::name>>::value> {}
991 
992  CEREAL_MAKE_IS_SPECIALIZED_IMPL(member_serialize);
993  CEREAL_MAKE_IS_SPECIALIZED_IMPL(member_load_save);
994  CEREAL_MAKE_IS_SPECIALIZED_IMPL(member_load_save_minimal);
995  CEREAL_MAKE_IS_SPECIALIZED_IMPL(non_member_serialize);
996  CEREAL_MAKE_IS_SPECIALIZED_IMPL(non_member_load_save);
997  CEREAL_MAKE_IS_SPECIALIZED_IMPL(non_member_load_save_minimal);
998 
999  #undef CEREAL_MAKE_IS_SPECIALIZED_IMPL
1000 
1002  template <class T, class A>
1003  struct count_specializations : std::integral_constant<int,
1004  is_specialized_member_serialize<T, A>::value +
1005  is_specialized_member_load_save<T, A>::value +
1006  is_specialized_member_load_save_minimal<T, A>::value +
1007  is_specialized_non_member_serialize<T, A>::value +
1008  is_specialized_non_member_load_save<T, A>::value +
1009  is_specialized_non_member_load_save_minimal<T, A>::value> {};
1010  } // namespace detail
1011 
1013  template <class T, class A>
1014  struct is_specialized : std::integral_constant<bool,
1015  detail::is_specialized_member_serialize<T, A>::value ||
1016  detail::is_specialized_member_load_save<T, A>::value ||
1017  detail::is_specialized_member_load_save_minimal<T, A>::value ||
1018  detail::is_specialized_non_member_serialize<T, A>::value ||
1019  detail::is_specialized_non_member_load_save<T, A>::value ||
1020  detail::is_specialized_non_member_load_save_minimal<T, A>::value>
1021  {
1022  static_assert(detail::count_specializations<T, A>::value <= 1, "More than one explicit specialization detected for type.");
1023  };
1024 
1026 
1028  #define CEREAL_MAKE_IS_SPECIALIZED_ASSERT(name, versioned_name, print_name, spec_name) \
1029  static_assert( (is_specialized<T, A>::value && detail::is_specialized_##spec_name<T, A>::value && \
1030  (has_##name<T, A>::value || has_##versioned_name<T, A>::value)) \
1031  || !(is_specialized<T, A>::value && detail::is_specialized_##spec_name<T, A>::value), \
1032  "cereal detected " #print_name " specialization but no " #print_name " serialize function" )
1033 
1035 
1037  #define CEREAL_MAKE_IS_SPECIALIZED(name, versioned_name, spec_name) \
1038  template <class T, class A> \
1039  struct is_specialized_##name : std::integral_constant<bool, \
1040  is_specialized<T, A>::value && detail::is_specialized_##spec_name<T, A>::value> \
1041  { CEREAL_MAKE_IS_SPECIALIZED_ASSERT(name, versioned_name, name, spec_name); }; \
1042  template <class T, class A> \
1043  struct is_specialized_##versioned_name : std::integral_constant<bool, \
1044  is_specialized<T, A>::value && detail::is_specialized_##spec_name<T, A>::value> \
1045  { CEREAL_MAKE_IS_SPECIALIZED_ASSERT(name, versioned_name, versioned_name, spec_name); }
1046 
1047  CEREAL_MAKE_IS_SPECIALIZED(member_serialize, member_versioned_serialize, member_serialize);
1048  CEREAL_MAKE_IS_SPECIALIZED(non_member_serialize, non_member_versioned_serialize, non_member_serialize);
1049 
1050  CEREAL_MAKE_IS_SPECIALIZED(member_save, member_versioned_save, member_load_save);
1051  CEREAL_MAKE_IS_SPECIALIZED(non_member_save, non_member_versioned_save, non_member_load_save);
1052  CEREAL_MAKE_IS_SPECIALIZED(member_load, member_versioned_load, member_load_save);
1053  CEREAL_MAKE_IS_SPECIALIZED(non_member_load, non_member_versioned_load, non_member_load_save);
1054 
1055  CEREAL_MAKE_IS_SPECIALIZED(member_save_minimal, member_versioned_save_minimal, member_load_save_minimal);
1056  CEREAL_MAKE_IS_SPECIALIZED(non_member_save_minimal, non_member_versioned_save_minimal, non_member_load_save_minimal);
1057  CEREAL_MAKE_IS_SPECIALIZED(member_load_minimal, member_versioned_load_minimal, member_load_save_minimal);
1058  CEREAL_MAKE_IS_SPECIALIZED(non_member_load_minimal, non_member_versioned_load_minimal, non_member_load_save_minimal);
1059 
1060  #undef CEREAL_MAKE_IS_SPECIALIZED_ASSERT
1061  #undef CEREAL_MAKE_IS_SPECIALIZED
1062 
1063  // ######################################################################
1064  // detects if a type has any active minimal output serialization
1065  template <class T, class OutputArchive>
1066  struct has_minimal_output_serialization : std::integral_constant<bool,
1067  is_specialized_member_save_minimal<T, OutputArchive>::value ||
1068  ((has_member_save_minimal<T, OutputArchive>::value ||
1069  has_non_member_save_minimal<T, OutputArchive>::value ||
1070  has_member_versioned_save_minimal<T, OutputArchive>::value ||
1071  has_non_member_versioned_save_minimal<T, OutputArchive>::value) &&
1072  !(is_specialized_member_serialize<T, OutputArchive>::value ||
1073  is_specialized_member_save<T, OutputArchive>::value))> {};
1074 
1075  // ######################################################################
1076  // detects if a type has any active minimal input serialization
1077  template <class T, class InputArchive>
1078  struct has_minimal_input_serialization : std::integral_constant<bool,
1079  is_specialized_member_load_minimal<T, InputArchive>::value ||
1080  ((has_member_load_minimal<T, InputArchive>::value ||
1081  has_non_member_load_minimal<T, InputArchive>::value ||
1082  has_member_versioned_load_minimal<T, InputArchive>::value ||
1083  has_non_member_versioned_load_minimal<T, InputArchive>::value) &&
1084  !(is_specialized_member_serialize<T, InputArchive>::value ||
1085  is_specialized_member_load<T, InputArchive>::value))> {};
1086 
1087  // ######################################################################
1088  namespace detail
1089  {
1091 
1092  template <class T, class OutputArchive>
1093  struct count_output_serializers : std::integral_constant<int,
1094  count_specializations<T, OutputArchive>::value ? count_specializations<T, OutputArchive>::value :
1095  has_member_save<T, OutputArchive>::value +
1096  has_non_member_save<T, OutputArchive>::value +
1097  has_member_serialize<T, OutputArchive>::value +
1098  has_non_member_serialize<T, OutputArchive>::value +
1099  has_member_save_minimal<T, OutputArchive>::value +
1100  has_non_member_save_minimal<T, OutputArchive>::value +
1101  /*-versioned---------------------------------------------------------*/
1102  has_member_versioned_save<T, OutputArchive>::value +
1103  has_non_member_versioned_save<T, OutputArchive>::value +
1104  has_member_versioned_serialize<T, OutputArchive>::value +
1105  has_non_member_versioned_serialize<T, OutputArchive>::value +
1106  has_member_versioned_save_minimal<T, OutputArchive>::value +
1107  has_non_member_versioned_save_minimal<T, OutputArchive>::value> {};
1108  }
1109 
1110  template <class T, class OutputArchive>
1111  struct is_output_serializable : std::integral_constant<bool,
1112  detail::count_output_serializers<T, OutputArchive>::value == 1> {};
1113 
1114  // ######################################################################
1115  namespace detail
1116  {
1118 
1119  template <class T, class InputArchive>
1120  struct count_input_serializers : std::integral_constant<int,
1121  count_specializations<T, InputArchive>::value ? count_specializations<T, InputArchive>::value :
1122  has_member_load<T, InputArchive>::value +
1123  has_non_member_load<T, InputArchive>::value +
1124  has_member_serialize<T, InputArchive>::value +
1125  has_non_member_serialize<T, InputArchive>::value +
1126  has_member_load_minimal<T, InputArchive>::value +
1127  has_non_member_load_minimal<T, InputArchive>::value +
1128  /*-versioned---------------------------------------------------------*/
1129  has_member_versioned_load<T, InputArchive>::value +
1130  has_non_member_versioned_load<T, InputArchive>::value +
1131  has_member_versioned_serialize<T, InputArchive>::value +
1132  has_non_member_versioned_serialize<T, InputArchive>::value +
1133  has_member_versioned_load_minimal<T, InputArchive>::value +
1134  has_non_member_versioned_load_minimal<T, InputArchive>::value> {};
1135  }
1136 
1137  template <class T, class InputArchive>
1138  struct is_input_serializable : std::integral_constant<bool,
1139  detail::count_input_serializers<T, InputArchive>::value == 1> {};
1140 
1141  // ######################################################################
1142  // Base Class Support
1143  namespace detail
1144  {
1146  {
1147  template<class T>
1148  base_class_id(T const * const t) :
1149  type(typeid(T)),
1150  ptr(t),
1151  hash(std::hash<std::type_index>()(typeid(T)) ^ (std::hash<void const *>()(t) << 1))
1152  { }
1153 
1154  bool operator==(base_class_id const & other) const
1155  { return (type == other.type) && (ptr == other.ptr); }
1156 
1157  std::type_index type;
1158  void const * ptr;
1159  size_t hash;
1160  };
1161  struct base_class_id_hash { size_t operator()(base_class_id const & id) const { return id.hash; } };
1162  } // namespace detail
1163 
1164  namespace detail
1165  {
1167  struct BaseCastBase {};
1168 
1169  template <class>
1171 
1172  template <template<typename> class Cast, class Base>
1173  struct get_base_class<Cast<Base>>
1174  {
1175  using type = Base;
1176  };
1177 
1179  template <class Cast, template<class, class> class Test, class Archive,
1180  bool IsBaseCast = std::is_base_of<BaseCastBase, Cast>::value>
1181  struct has_minimal_base_class_serialization_impl : Test<typename get_base_class<Cast>::type, Archive>
1182  { };
1183 
1185  template <class Cast, template<class, class> class Test, class Archive>
1186  struct has_minimal_base_class_serialization_impl<Cast,Test, Archive, false> : std::false_type
1187  { };
1188  }
1189 
1191 
1194  template <class Cast, template<class, class> class Test, class Archive>
1196  { };
1197 
1198 
1199  // ######################################################################
1200  namespace detail
1201  {
1203  {
1204  template <class U>
1205  static auto (check)( U const & t ) -> decltype( ::cereal::access::shared_from_this(t), std::true_type() );
1206 
1207  static auto (check)( ... ) -> decltype( std::false_type() );
1208 
1209  template <class U>
1210  static auto get( U const & t ) -> decltype( t.shared_from_this() );
1211  };
1212  }
1213 
1215  template<class T>
1216  struct has_shared_from_this : decltype((detail::shared_from_this_wrapper::check)(std::declval<T>()))
1217  { };
1218 
1220  template <class T>
1222  {
1223  private:
1224  using PtrType = decltype(detail::shared_from_this_wrapper::get(std::declval<T>()));
1225  public:
1227  using type = typename std::decay<typename PtrType::element_type>::type;
1228  };
1229 
1230  // ######################################################################
1232 
1238  template <class T, bool IsCerealMinimalTrait = std::is_base_of<detail::NoConvertBase, T>::value>
1240  {
1241  using type = T;
1242  };
1243 
1245  template <class T>
1246  struct strip_minimal<T, true>
1247  {
1248  using type = typename T::type;
1249  };
1250 
1251  // ######################################################################
1253  template <class T>
1255  {
1256  #ifdef CEREAL_OLDER_GCC
1257  template <class TT, class SFINAE = void>
1258  struct test : no {};
1259  template <class TT>
1260  struct test<TT, typename detail::Void< decltype( cereal::access::construct<TT>() ) >::type> : yes {};
1261  static const bool value = test<T>();
1262  #else // NOT CEREAL_OLDER_GCC =========================================
1263  template <class TT>
1264  static auto test(int) -> decltype( cereal::access::construct<TT>(), yes());
1265  template <class>
1266  static no test(...);
1267  static const bool value = std::is_same<decltype(test<T>(0)), yes>::value;
1268  #endif // NOT CEREAL_OLDER_GCC
1269  };
1270 
1271  // ######################################################################
1272  namespace detail
1273  {
1275  template <class A>
1276  using decay_archive = typename std::decay<typename strip_minimal<A>::type>::type;
1277  }
1278 
1280 
1289  template <class ArchiveT, class CerealArchiveT>
1290  struct is_same_archive : std::integral_constant<bool,
1291  std::is_same<detail::decay_archive<ArchiveT>, CerealArchiveT>::value>
1292  { };
1293 
1294  // ######################################################################
1296 
1315  #define CEREAL_ARCHIVE_RESTRICT(INTYPE, OUTTYPE) \
1316  typename std::enable_if<cereal::traits::is_same_archive<Archive, INTYPE>::value || cereal::traits::is_same_archive<Archive, OUTTYPE>::value, void>::type
1317 
1319 
1321  struct TextArchive {};
1322 
1324  template <class A>
1325  struct is_text_archive : std::integral_constant<bool,
1326  std::is_base_of<TextArchive, detail::decay_archive<A>>::value>
1327  { };
1328  } // namespace traits
1329 
1330  // ######################################################################
1331  namespace detail
1332  {
1333  template <class T, class A,
1336  bool NonMember = traits::has_non_member_load_and_construct<T, A>::value,
1337  bool NonMemberVersioned = traits::has_non_member_versioned_load_and_construct<T, A>::value>
1338  struct Construct
1339  {
1341  "cereal found more than one compatible load_and_construct function for the provided type and archive combination. \n\n "
1342  "Types must either have a member load_and_construct function or a non-member specialization of LoadAndConstruct (you may not mix these). \n "
1343  "In addition, you may not mix versioned with non-versioned load_and_construct functions. \n\n " );
1344  static T * load_andor_construct( A & /*ar*/, construct<T> & /*construct*/ )
1345  { return nullptr; }
1346  };
1347 
1348  // no load and construct case
1349  template <class T, class A>
1350  struct Construct<T, A, false, false, false, false>
1351  {
1353  "Trying to serialize a an object with no default constructor. \n\n "
1354  "Types must either be default constructible or define either a member or non member Construct function. \n "
1355  "Construct functions generally have the signature: \n\n "
1356  "template <class Archive> \n "
1357  "static void load_and_construct(Archive & ar, cereal::construct<T> & construct) \n "
1358  "{ \n "
1359  " var a; \n "
1360  " ar( a ) \n "
1361  " construct( a ); \n "
1362  "} \n\n" );
1363  static T * load_andor_construct()
1364  { return ::cereal::access::construct<T>(); }
1365  };
1366 
1367  // member non-versioned
1368  template <class T, class A>
1369  struct Construct<T, A, true, false, false, false>
1370  {
1371  static void load_andor_construct( A & ar, construct<T> & construct )
1372  {
1373  access::load_and_construct<T>( ar, construct );
1374  }
1375  };
1376 
1377  // member versioned
1378  template <class T, class A>
1379  struct Construct<T, A, false, true, false, false>
1380  {
1381  static void load_andor_construct( A & ar, construct<T> & construct )
1382  {
1383  const auto version = ar.template loadClassVersion<T>();
1384  access::load_and_construct<T>( ar, construct, version );
1385  }
1386  };
1387 
1388  // non-member non-versioned
1389  template <class T, class A>
1390  struct Construct<T, A, false, false, true, false>
1391  {
1392  static void load_andor_construct( A & ar, construct<T> & construct )
1393  {
1395  }
1396  };
1397 
1398  // non-member versioned
1399  template <class T, class A>
1400  struct Construct<T, A, false, false, false, true>
1401  {
1402  static void load_andor_construct( A & ar, construct<T> & construct )
1403  {
1404  const auto version = ar.template loadClassVersion<T>();
1406  }
1407  };
1408  } // namespace detail
1409 } // namespace cereal
1410 
1411 #endif // CEREAL_DETAILS_TRAITS_HPP_
cereal::traits::detail::NoConvertRef::type
Source type
Used to get underlying type easily.
Definition: traits.hpp:638
CEREAL_MAKE_IS_SPECIALIZED_IMPL
#define CEREAL_MAKE_IS_SPECIALIZED_IMPL(name)
Create a test for a cereal::specialization entry.
Definition: traits.hpp:987
cereal::traits::detail::NoConvertRef
A struct that prevents implicit conversion.
Definition: traits.hpp:636
CEREAL_MAKE_HAS_NON_MEMBER_TEST
#define CEREAL_MAKE_HAS_NON_MEMBER_TEST(test_name, func, versioned)
Creates a test for whether a non const non-member function exists.
Definition: traits.hpp:217
cereal::traits::detail::EnableIfHelper
Definition: traits.hpp:79
cereal::traits::detail::shared_from_this_wrapper
Definition: traits.hpp:1202
cereal::traits::strip_minimal
Extracts the true type from something possibly wrapped in a cereal NoConvert.
Definition: traits.hpp:1239
cereal::traits::detail::decay_archive
typename std::decay< typename strip_minimal< A >::type >::type decay_archive
Removes all qualifiers and minimal wrappers from an archive.
Definition: traits.hpp:1276
cereal::traits::detail::get_output_from_input
Definition: traits.hpp:154
DisableIf
typename detail::DisableIfHelper< Conditions... >::type DisableIf
Provides a way to disable a function if conditions are met.
Definition: traits.hpp:148
cereal::traits::detail::delay_static_assert
Used to delay a static_assert until template instantiation.
Definition: traits.hpp:57
cereal::construct
Used to construct types with no default constructor.
Definition: access.hpp:164
cereal::traits::detail::count_output_serializers
The number of output serialization functions available.
Definition: traits.hpp:1093
CEREAL_MAKE_IS_SPECIALIZED
#define CEREAL_MAKE_IS_SPECIALIZED(name, versioned_name, spec_name)
Generates a test for specialization for versioned and unversioned functions.
Definition: traits.hpp:1037
CEREAL_MAKE_HAS_MEMBER_SAVE_IMPL
#define CEREAL_MAKE_HAS_MEMBER_SAVE_IMPL(test_name, versioned)
Creates a test for whether a member save function exists.
Definition: traits.hpp:300
cereal::traits::detail::base_class_id_hash
Definition: traits.hpp:1161
cereal::traits::detail::meta_bool_and
Definition: traits.hpp:70
CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_TEST
#define CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_TEST(test_name)
Creates a test for whether a member save_minimal function exists.
Definition: traits.hpp:502
cereal::traits::detail::NoConvertBase
Used to help strip away conversion wrappers.
Definition: traits.hpp:610
cereal::traits::detail::meta_bool_or
Definition: traits.hpp:73
cereal::LoadAndConstruct
A class that allows cereal to load smart pointers to types that have no default constructor.
Definition: access.hpp:108
cereal::traits::is_minimal_type
Definition: traits.hpp:413
CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_IMPL
#define CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_IMPL(test_name, versioned)
Creates a test for whether a member load_minimal function exists.
Definition: traits.hpp:692
CEREAL_MAKE_HAS_NON_MEMBER_SAVE_MINIMAL_TEST
#define CEREAL_MAKE_HAS_NON_MEMBER_SAVE_MINIMAL_TEST(test_name, versioned)
Creates a test for whether a non-member save_minimal function exists.
Definition: traits.hpp:541
cereal::traits::has_invalid_output_versioning
Definition: traits.hpp:965
access.hpp
Access control and default construction.
cereal::traits::has_invalid_input_versioning
Definition: traits.hpp:975
cereal::traits::detail::NoConvertConstRef::type
Source type
Used to get underlying type easily.
Definition: traits.hpp:620
CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_HELPERS_IMPL
#define CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_HELPERS_IMPL(test_name, versioned)
Creates helpers for minimal save functions.
Definition: traits.hpp:482
CEREAL_SERIALIZE_FUNCTION_NAME
#define CEREAL_SERIALIZE_FUNCTION_NAME
The serialization/deserialization function name to search for.
Definition: macros.hpp:78
cereal::traits::has_member_versioned_load_and_construct
Member load and construct check (versioned)
Definition: traits.hpp:903
CEREAL_SAVE_MINIMAL_FUNCTION_NAME
#define CEREAL_SAVE_MINIMAL_FUNCTION_NAME
The serialization (save_minimal) function name to search for.
Definition: macros.hpp:106
cereal::traits::is_same_archive
Checks if the provided archive type is equal to some cereal archive type.
Definition: traits.hpp:1290
cereal::traits::has_member_save
Definition: traits.hpp:327
macros.hpp
Preprocessor macros that can customise the cereal library.
CEREAL_LOAD_FUNCTION_NAME
#define CEREAL_LOAD_FUNCTION_NAME
The deserialization (load) function name to search for.
Definition: macros.hpp:85
cereal::traits::detail::base_class_id
Definition: traits.hpp:1145
cereal::detail::Construct
Definition: traits.hpp:1338
cereal::traits::has_member_load_and_construct
Member load and construct check.
Definition: traits.hpp:898
cereal::traits::TextArchive
Type traits only struct used to mark an archive as human readable (text based)
Definition: traits.hpp:1321
cereal::traits::is_default_constructible
Determines whether the class T can be default constructed by cereal::access.
Definition: traits.hpp:1254
cereal::traits::detail::has_minimal_base_class_serialization_impl
Base class cast, behave as the test.
Definition: traits.hpp:1181
cereal::traits::is_text_archive
Checks if an archive is a text archive (human readable)
Definition: traits.hpp:1325
CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_HELPERS_IMPL
#define CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_HELPERS_IMPL(load_test_name, save_test_name, save_test_prefix, versioned)
Creates helpers for minimal load functions.
Definition: traits.hpp:731
CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_TEST
#define CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_TEST(load_test_name, load_test_prefix)
Creates a test for whether a member load_minimal function exists.
Definition: traits.hpp:764
cereal::traits::has_minimal_base_class_serialization
Checks to see if the base class used in a cast has a minimal serialization.
Definition: traits.hpp:1195
cereal::traits::is_output_serializable
Definition: traits.hpp:1111
cereal::traits::detail::BaseCastBase
Common base type for base class casting.
Definition: traits.hpp:1167
cereal::traits::has_member_versioned_save
Definition: traits.hpp:340
CEREAL_MAKE_HAS_MEMBER_TEST
#define CEREAL_MAKE_HAS_MEMBER_TEST(name, test_name, versioned)
Creates a test for whether a non const member function exists.
Definition: traits.hpp:196
cereal::traits::has_shared_from_this
Determine if T or any base class of T has inherited from std::enable_shared_from_this.
Definition: traits.hpp:1216
cereal::traits::detail::is_string
Definition: traits.hpp:405
cereal::traits::get_shared_from_this_base
Get the type of the base class of T which inherited from std::enable_shared_from_this.
Definition: traits.hpp:1221
cereal::traits::is_specialized
Check if any specialization exists for a type.
Definition: traits.hpp:1014
cereal::traits::detail::count_specializations
Number of specializations detected.
Definition: traits.hpp:1003
cereal::traits::detail::DisableIfHelper
Definition: traits.hpp:82
cereal::traits::detail::get_base_class
Definition: traits.hpp:1170
cereal::traits::detail::has_member_versioned_load_and_construct_impl
Definition: traits.hpp:891
EnableIf
typename detail::EnableIfHelper< Conditions... >::type EnableIf
Provides a way to enable a function if conditions are met.
Definition: traits.hpp:116
cereal::traits::has_minimal_input_serialization
Definition: traits.hpp:1078
CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_IMPL
#define CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_IMPL(test_name, versioned)
Creates implementation details for whether a member save_minimal function exists.
Definition: traits.hpp:449
cereal::traits::detail::has_member_load_and_construct_impl
Definition: traits.hpp:886
cereal::traits::detail::get_input_from_output
Definition: traits.hpp:161
cereal::traits::detail::count_input_serializers
The number of input serialization functions available.
Definition: traits.hpp:1120
cereal::traits::has_minimal_output_serialization
Definition: traits.hpp:1066
cereal::traits::detail::NoConvertConstRef
A struct that prevents implicit conversion.
Definition: traits.hpp:618
cereal::traits::get_shared_from_this_base::type
typename std::decay< typename PtrType::element_type >::type type
The type of the base of T that inherited from std::enable_shared_from_this.
Definition: traits.hpp:1227
CEREAL_LOAD_MINIMAL_FUNCTION_NAME
#define CEREAL_LOAD_MINIMAL_FUNCTION_NAME
The deserialization (load_minimal) function name to search for.
Definition: macros.hpp:99
CEREAL_MAKE_HAS_NON_MEMBER_LOAD_AND_CONSTRUCT_TEST
#define CEREAL_MAKE_HAS_NON_MEMBER_LOAD_AND_CONSTRUCT_TEST(test_name, versioned)
Creates a test for whether a non-member load_and_construct specialization exists.
Definition: traits.hpp:910
CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST
#define CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST(test_name, save_name, versioned)
Creates a test for whether a non-member load_minimal function exists.
Definition: traits.hpp:818
CEREAL_MAKE_HAS_NON_MEMBER_SAVE_TEST
#define CEREAL_MAKE_HAS_NON_MEMBER_SAVE_TEST(test_name, versioned)
Creates a test for whether a non-member save function exists.
Definition: traits.hpp:358
cereal::traits::detail::AnyConvert
A type that can implicitly convert to anything else.
Definition: traits.hpp:654
cereal::traits::is_input_serializable
Definition: traits.hpp:1138
cereal::traits::has_load_and_construct
Non member load and construct check.
Definition: traits.hpp:939
cereal::traits::has_non_member_split
Definition: traits.hpp:959
CEREAL_MAKE_VERSIONED_TEST
#define CEREAL_MAKE_VERSIONED_TEST
Used to convert a MAKE_HAS_XXX macro into a versioned variant.
Definition: traits.hpp:178
cereal::traits::detail::sfinae
sfinae
Return type for SFINAE Enablers.
Definition: traits.hpp:66
cereal::traits::has_member_split
Definition: traits.hpp:953