2 \brief Internal type trait support
5 Copyright (c) 2014, Randolph Voorhies, Shane Grant
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.
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.
30 #ifndef CEREAL_DETAILS_TRAITS_HPP_
31 #define CEREAL_DETAILS_TRAITS_HPP_
34 #if (__GNUC__ == 4 && __GNUC_MINOR__ <= 7)
35 #define CEREAL_OLDER_GCC
36 #endif // gcc 4.7 or earlier
39 #include <type_traits>
42 #include <cereal/access.hpp>
48 typedef std::true_type yes;
49 typedef std::false_type no;
53 //! Used to delay a static_assert until template instantiation
55 struct delay_static_assert : std::false_type {};
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
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) \
76 template <class T, class A> \
77 struct has_member_##name##_impl \
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; \
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
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) \
96 template <class T, class A> \
97 struct has_non_member_##name##_impl \
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; \
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> {}
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) \
123 template <class T, class A> \
124 struct has_member_versioned_##name##_impl \
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; \
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
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) \
143 template <class T, class A> \
144 struct has_non_member_versioned_##name##_impl \
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; \
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> {}
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> {};
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> {};
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>
175 // ######################################################################
177 CEREAL_MAKE_HAS_MEMBER_TEST(serialize);
179 // ######################################################################
180 // Member Serialize (versioned)
181 CEREAL_MAKE_HAS_MEMBER_VERSIONED_TEST(serialize);
183 // ######################################################################
184 // Non Member Serialize
185 CEREAL_MAKE_HAS_NON_MEMBER_TEST(serialize);
187 // ######################################################################
188 // Non Member Serialize (versioned)
189 CEREAL_MAKE_HAS_NON_MEMBER_VERSIONED_TEST(serialize);
191 // ######################################################################
193 CEREAL_MAKE_HAS_MEMBER_TEST(load);
195 // ######################################################################
196 // Member Load (versioned)
197 CEREAL_MAKE_HAS_MEMBER_VERSIONED_TEST(load);
199 // ######################################################################
201 CEREAL_MAKE_HAS_NON_MEMBER_TEST(load);
203 // ######################################################################
204 // Non Member Load (versioned)
205 CEREAL_MAKE_HAS_NON_MEMBER_VERSIONED_TEST(load);
207 // ######################################################################
211 template <class T, class A>
212 struct has_member_save_impl
214 #ifdef CEREAL_OLDER_GCC
215 template <class TT, class AA, class SFINAE = void>
217 template <class TT, class 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>();
222 template <class TT, class AA, class SFINAE = void>
223 struct test2 : no {};
224 template <class TT, class 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>
233 static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
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
242 } // end namespace detail
244 template <class T, class A>
245 struct has_member_save : std::integral_constant<bool, detail::has_member_save_impl<T, A>::value>
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" );
253 // ######################################################################
254 // Member Save (versioned)
257 template <class T, class A>
258 struct has_member_versioned_save_impl
260 #ifdef CEREAL_OLDER_GCC
261 template <class TT, class AA, class SFINAE = void>
263 template <class TT, class 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>();
268 template <class TT, class AA, class SFINAE = void>
269 struct test2 : no {};
270 template <class TT, class 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>
279 static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
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
288 } // end namespace detail
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>
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" );
299 // ######################################################################
303 template <class T, class A>
304 struct has_non_member_save_impl
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>
310 static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
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;
318 } // end namespace detail
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>
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" );
329 // ######################################################################
330 // Non-Member Save (versioned)
333 template <class T, class A>
334 struct has_non_member_versioned_save_impl
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>
340 static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
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;
348 } // end namespace detail
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>
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" );
359 // ######################################################################
363 // Determines if the provided type is an std::string
364 template <class> struct is_string : std::false_type {};
366 template <class CharT, class Traits, class Alloc>
367 struct is_string<std::basic_string<CharT, Traits, Alloc>> : std::true_type {};
370 // Determines if the type is valid for use with a minimal serialize function
372 struct is_minimal_type : std::integral_constant<bool, detail::is_string<T>::value ||
373 std::is_arithmetic<T>::value> {};
375 // ######################################################################
376 // Member Save Minimal
379 template <class T, class A>
380 struct has_member_save_minimal_impl
382 #ifdef CEREAL_OLDER_GCC
383 template <class TT, class AA, class SFINAE = void>
385 template <class TT, class 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>();
390 template <class TT, class AA, class SFINAE = void>
391 struct test2 : no {};
392 template <class TT, class 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>
401 static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
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
410 static const bool valid = value || !not_const_type;
413 template <class T, class A, bool Valid>
414 struct get_member_save_minimal_type { typedef void type; };
416 template <class T, class A>
417 struct get_member_save_minimal_type<T, A, true>
419 typedef decltype( cereal::access::member_save_minimal( std::declval<A const &>(), std::declval<T const &>() ) ) type;
421 } // end namespace detail
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>
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" );
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" );
437 // ######################################################################
438 // Member Save Minimal (versioned)
441 template <class T, class A>
442 struct has_member_versioned_save_minimal_impl
444 #ifdef CEREAL_OLDER_GCC
445 template <class TT, class AA, class SFINAE = void>
447 template <class TT, class 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>();
452 template <class TT, class AA, class SFINAE = void>
453 struct test2 : no {};
454 template <class TT, class 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>
463 static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
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
472 static const bool valid = value || !not_const_type;
475 template <class T, class A, bool Valid>
476 struct get_member_versioned_save_minimal_type { typedef void type; };
478 template <class T, class A>
479 struct get_member_versioned_save_minimal_type<T, A, true>
481 typedef decltype( cereal::access::member_save_minimal( std::declval<A const &>(), std::declval<T const &>(), 0 ) ) type;
483 } // end namespace detail
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>
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" );
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" );
499 // ######################################################################
500 // Non-Member Save Minimal
503 template <class T, class A>
504 struct has_non_member_save_minimal_impl
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>
510 static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
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;
518 static const bool valid = value || !not_const_type;
521 template <class T, class A, bool Valid>
522 struct get_non_member_save_minimal_type { typedef void type; };
524 template <class T, class A>
525 struct get_non_member_save_minimal_type <T, A, true>
527 typedef decltype( save_minimal( std::declval<A const &>(), std::declval<T const &>() ) ) type;
529 } // end namespace detail
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>
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" );
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" );
545 // ######################################################################
546 // Non-Member Save Minimal (versioned)
549 template <class T, class A>
550 struct has_non_member_versioned_save_minimal_impl
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>
556 static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
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;
564 static const bool valid = value || !not_const_type;
567 template <class T, class A, bool Valid>
568 struct get_non_member_versioned_save_minimal_type { typedef void type; };
570 template <class T, class A>
571 struct get_non_member_versioned_save_minimal_type <T, A, true>
573 typedef decltype( save_minimal( std::declval<A const &>(), std::declval<T const &>(), 0 ) ) type;
575 } // end namespace detail
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>
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" );
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" );
591 // ######################################################################
592 // Member Load Minimal
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 {};
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 &.
607 @tparam Source the type of the original source */
608 template <class Source>
609 struct NoConvertConstRef : NoConvertBase
611 typedef Source type; //!< Used to get underlying type easily
613 template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
614 operator Dest () = delete;
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 & ();
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 &.
625 @tparam Source the type of the original source */
626 template <class Source>
627 struct NoConvertRef : NoConvertBase
629 typedef Source type; //!< Used to get underlying type easily
631 template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
632 operator Dest () = delete;
635 template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
636 operator Dest const & () = delete;
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>
644 //! A type that can implicitly convert to anything else
647 template <class Dest>
650 template <class Dest>
651 operator Dest const & () const;
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 {};
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
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>
677 static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
680 template <class T, class A, class U>
681 struct has_member_load_minimal_type_impl
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>
687 static const bool value = std::is_same<decltype(test<T, A, U>(0)), yes>::value;
689 #endif // NOT CEREAL_OLDER_GCC
691 template <class T, class A, bool Valid>
692 struct has_member_load_minimal_wrapper : std::false_type {};
694 template <class T, class A>
695 struct has_member_load_minimal_wrapper<T, A, true>
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." );
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;
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." );
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> {};
714 // ######################################################################
715 // Member Load Minimal (versioned)
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 {};
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
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>
738 static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;
741 template <class T, class A, class U>
742 struct has_member_versioned_load_minimal_type_impl
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>
748 static const bool value = std::is_same<decltype(test<T, A, U>(0)), yes>::value;
750 #endif // NOT CEREAL_OLDER_GCC
752 template <class T, class A, bool Valid>
753 struct has_member_versioned_load_minimal_wrapper : std::false_type {};
755 template <class T, class A>
756 struct has_member_versioned_load_minimal_wrapper<T, A, true>
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." );
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;
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." );
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> {};
775 // ######################################################################
776 // Non-Member Load Minimal
779 #ifdef CEREAL_OLDER_GCC
780 void load_minimal(); // prevents nonsense complaining about not finding this
782 #endif // CEREAL_OLDER_GCC
784 // See notes from member load_minimal
785 template <class T, class A, class U = void>
786 struct has_non_member_load_minimal_impl
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;
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;
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;
807 template <class T, class A, bool Valid>
808 struct has_non_member_load_minimal_wrapper : std::false_type {};
810 template <class T, class A>
811 struct has_non_member_load_minimal_wrapper<T, A, true>
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." );
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;
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" );
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> {};
832 // ######################################################################
833 // Non-Member Load Minimal (versioned)
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
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;
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;
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;
859 template <class T, class A, bool Valid>
860 struct has_non_member_versioned_load_minimal_wrapper : std::false_type {};
862 template <class T, class A>
863 struct has_non_member_versioned_load_minimal_wrapper<T, A, true>
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." );
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;
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" );
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> {};
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)> {};
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)> {};
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> {};
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> {};
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)> {};
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)> {};
950 // ######################################################################
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> {};
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> {};
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> {};
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> {};
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> {};
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> {};
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
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>
997 static_assert(detail::is_specialized_error<T, A>::value, "More than one explicit specialization detected for type.");
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>
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" );
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>
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" );
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>
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" );
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>
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" );
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>
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" );
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>
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" );
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>
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" );
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>
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" );
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>
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" );
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>
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" );
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))> {};
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))> {};
1124 // ######################################################################
1127 struct base_class_id
1130 base_class_id(T const * const t) :
1133 hash(std::hash<std::type_index>()(typeid(T)) ^ (std::hash<void const *>()(t) << 1))
1136 bool operator==(base_class_id const & other) const
1137 { return (type == other.type) && (ptr == other.ptr); }
1139 std::type_index type;
1143 struct base_class_id_hash { size_t operator()(base_class_id const & id) const { return id.hash; } };
1144 } // namespace detail
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.
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.
1154 For example, if we want to limit a serialize to only work with binary serialization:
1157 template <class Archive>
1158 CEREAL_ARCHIVE_RESTRICT(BinaryInputArchive, BinaryOutputArchive)
1159 serialize( Archive & ar, MyCoolType & m )
1165 If you need to do more restrictions in your enable_if, you will need to do this by hand.
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
1170 // ######################################################################
1173 struct shared_from_this_wrapper
1176 static auto check( U const & t ) -> decltype( ::cereal::access::shared_from_this(t), std::true_type() );
1178 static auto check( ... ) -> decltype( std::false_type() );
1181 static auto get( U const & t ) -> decltype( t.shared_from_this() );
1185 // works around the lack of decltype inheritance in GCC 4.6
1187 struct shared_wrapper
1189 typedef decltype(detail::shared_from_this_wrapper::check(std::declval<T>())) type;
1192 //! Determine if T or any base class of T has inherited from std::enable_shared_from_this
1194 struct has_shared_from_this : shared_wrapper<T>::type
1197 //! Get the type of the base class of T which inherited from std::enable_shared_from_this
1199 struct get_shared_from_this_base
1202 typedef decltype(detail::shared_from_this_wrapper::get(std::declval<T>())) PtrType;
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;
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.
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
1222 //! Specialization for types wrapped in a NoConvert
1224 struct strip_minimal<T, true>
1226 typedef typename T::type type;
1228 } // namespace traits
1230 // ######################################################################
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>
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*/ )
1243 struct is_default_constructible : std::is_constructible<T>{};
1244 template <class T, class A>
1245 struct Construct<T, A, false, false>
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 "
1256 " construct( a ); \n "
1258 static T * load_andor_construct()
1262 template <class T, class A>
1263 struct Construct<T, A, true, false>
1265 static void load_andor_construct( A & ar, construct<T> & construct )
1267 access::load_and_construct<T>( ar, construct );
1271 template <class T, class A>
1272 struct Construct<T, A, false, true>
1274 static void load_andor_construct( A & ar, construct<T> & construct )
1276 LoadAndConstruct<T>::load_and_construct( ar, construct );
1279 } // namespace detail
1280 } // namespace cereal
1282 #endif // CEREAL_DETAILS_TRAITS_HPP_