source: rrlib_rtti/type_traits.h @ 104:b27fd57fe3a6

17.03
Last change on this file since 104:b27fd57fe3a6 was 104:b27fd57fe3a6, checked in by Max Reichardt <mreichardt@…>, 3 years ago

Adds native support for std::pair, std::tuple, and rrlib::util::tEnumBasedFlags types. This includes some refactorings for this purpose.

File size: 21.5 KB
Line 
1//
2// You received this file as part of RRLib
3// Robotics Research Library
4//
5// Copyright (C) Finroc GbR (finroc.org)
6//
7// This program is free software; you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation; either version 2 of the License, or
10// (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License along
18// with this program; if not, write to the Free Software Foundation, Inc.,
19// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20//
21//----------------------------------------------------------------------
22/*!\file    rrlib/rtti/type_traits.h
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2012-02-05
27 *
28 * Various type traits required for rrlib_rtti.
29 * Most of them can be specialized.
30 * Further type traits related to generic operations are defined in generic_operations.h
31 *
32 */
33//----------------------------------------------------------------------
34#ifndef __rrlib__rtti__type_traits_h__
35#define __rrlib__rtti__type_traits_h__
36
37//----------------------------------------------------------------------
38// External includes (system with <>, local with "")
39//----------------------------------------------------------------------
40#include <type_traits>
41#include "rrlib/serialization/serialization.h"
42
43//----------------------------------------------------------------------
44// Internal includes with ""
45//----------------------------------------------------------------------
46#include "rrlib/rtti/generic_operations.h"
47#include "rrlib/rtti/detail/type_traits.h"
48#include "rrlib/rtti/detail/tTypeInfo.h"
49
50//----------------------------------------------------------------------
51// Namespace declaration
52//----------------------------------------------------------------------
53namespace rrlib
54{
55namespace rtti
56{
57
58//----------------------------------------------------------------------
59// Forward declarations / typedefs / enums
60//----------------------------------------------------------------------
61template <typename T>
62class tDataType;
63
64typedef util::tManagedConstCharPointer(*tGetTypenameFunction)(const tType& type);
65typedef std::vector<util::tManagedConstCharPointer>(*tGetTypenamesFunction)(const tType& type);
66
67/** Enum for classifying types */
68enum class tTypeClassification
69{
70  // Types with generated names
71  ARRAY = 0 << 12,
72  LIST = 1 << 12,
73  PAIR = 2 << 12,
74  TUPLE = 3 << 12,
75  ENUM_BASED_FLAGS = 4 << 12,
76  AUTO_NAMED = ENUM_BASED_FLAGS,
77
78  // Types with fixed names
79  INTEGRAL = 12 << 12,
80  OTHER_DATA_TYPE = 13 << 12,
81  NULL_TYPE = 14 << 12,
82  RPC_TYPE = 15 << 12,
83};
84
85//----------------------------------------------------------------------
86// Function declarations
87//----------------------------------------------------------------------
88
89/*!
90 * Type trait that indicates whether rrlib_rtti should consider the cast from TSource to TDestination to be implicit - e.g. leading to automatic casts in Finroc data ports.
91 * Unlike std::is_convertible, this trait should only be true if the cast is lossless for all possible values of TSource:
92 *   meaning there are no cases where this could lose precision or values could be outside of TDestination's range.
93 *
94 * This follows the defensive idea adopted in rrlib_rtti that automatic/implicit casting should never happen for cases where this could be erroneous.
95 */
96template <typename TSource, typename TDestination>
97struct IsImplicitlyConvertible
98{
99  /*! Enforce explicit casts (for arithmetic types)? */
100  enum { cENFORCE_EXPLICIT_CAST = std::is_arithmetic<TSource>::value && std::is_arithmetic<TDestination>::value &&
101                                  ((std::is_signed<TSource>::value && std::is_unsigned<TDestination>::value) ||   // sign-loss shall be explicit
102                                   (sizeof(TSource) > sizeof(TDestination) || // information-loss shall be explicit
103                                    // and also precision-loss
104                                    (sizeof(TSource) == sizeof(TDestination) && (std::is_integral<TSource>::value != std::is_integral<TDestination>::value || std::is_signed<TSource>::value == std::is_signed<TDestination>::value))))
105       };
106
107  /*! Defines whether cast is implicit in rrlib_rtti */
108  enum { value = std::is_convertible<TSource, TDestination>::value && (!cENFORCE_EXPLICIT_CAST) && (!std::is_enum<TSource>::value) && (!std::is_enum<TDestination>::value) };
109};
110
111/*!
112 * Type trait that can be specialized to indicate that type T and 'type' share the same memory layout and basic binary operations.
113 * This means specifically:
114 * (1) identical default-construction & destruction
115 * (2) identical DeepCopy() & Equals()  (see GenericOperations below)
116 * (3) (1) and (2) are also true for std::vector<T> and std::vector<type>
117 * (4) Casting from T to 'type' is possible (option will be offered by rrlib_rtti_conversion) and could safely be done with a reinterpret_cast<type&>.
118 *
119 * This is e.g. true for some wrapper classes (e.g. in rrlib_si_units) - and allows for major optimizations in rrlib_rrti type handling.
120 * (With respect to enums, std::underlying_type has similarities to the trait defined here.)
121 *
122 * In this sense, enum and signed integral types can be seen as having unsigned integral types as underlying types - which is defined below.
123 * The template needs to be specialized to support further types.
124 *
125 * Note: Operations (1), (2) and possibly binary serialization need not be defined for type T in order to be usable with rrlib_rtti - only for type 'type'.
126 *       Binary serialization & deserialization needs to be defined for T if cBINARY_SERIALIZATION_DIFFERS is set.
127 */
128template <typename T>
129struct UnderlyingType
130{
131  /*! Does not need to be defined by specializations */
132  enum tEnum { cENUM_TYPE = std::is_enum<T>::value };
133  typedef typename std::conditional<cENUM_TYPE, typename std::underlying_type<typename std::conditional<cENUM_TYPE, T, tEnum>::type>::type, T>::type tNonEnum;
134  enum { cSIGNED_INTEGRAL_TYPE = std::is_integral<tNonEnum>::value && std::is_signed<tNonEnum>::value };
135  typedef typename std::conditional<cSIGNED_INTEGRAL_TYPE, typename std::make_unsigned<typename std::conditional<cSIGNED_INTEGRAL_TYPE, tNonEnum, int>::type>::type, tNonEnum>::type tUnsigned;
136
137  /*! underlying type; is set to T if T does not wrap another type as specified in trait specification */
138  typedef tUnsigned type;
139
140  /*!
141   * True if 'type' can safely be converted to 'T' using a reinterpret_cast.
142   * This should not be set to true if e.g. the constructor of T checks or limits values.
143   */
144  enum { cREVERSE_CAST_VALID = cSIGNED_INTEGRAL_TYPE || std::is_same<T, type>::value };
145
146  /*! True if types T and 'type' have different binary serialization */
147  enum { cBINARY_SERIALIZATION_DIFFERS = cENUM_TYPE };
148
149  /*! True if types T and 'type' have different string and/or XML serialization */
150  enum { cOTHER_SERIALIZATION_DIFFERS = true };
151};
152
153template <typename T>
154struct UnderlyingType<std::vector<T>>
155{
156  typedef std::vector<typename UnderlyingType<T>::type> type;
157  enum { cREVERSE_CAST_VALID = UnderlyingType<T>::cREVERSE_CAST_VALID };
158  enum { cBINARY_SERIALIZATION_DIFFERS = UnderlyingType<T>::cBINARY_SERIALIZATION_DIFFERS };
159  enum { cOTHER_SERIALIZATION_DIFFERS = UnderlyingType<T>::cOTHER_SERIALIZATION_DIFFERS };
160};
161
162template <typename T, size_t N>
163struct UnderlyingType<std::array<T, N>>
164{
165  typedef std::array<typename UnderlyingType<T>::type, N> type;
166  enum { cREVERSE_CAST_VALID = UnderlyingType<T>::cREVERSE_CAST_VALID };
167  enum { cBINARY_SERIALIZATION_DIFFERS = UnderlyingType<T>::cBINARY_SERIALIZATION_DIFFERS };
168  enum { cOTHER_SERIALIZATION_DIFFERS = UnderlyingType<T>::cOTHER_SERIALIZATION_DIFFERS };
169};
170
171template <typename TFlag, typename TStorage>
172struct UnderlyingType<rrlib::util::tEnumBasedFlags<TFlag, TStorage>>
173{
174  typedef TStorage type;
175  enum { cREVERSE_CAST_VALID = true };
176  enum { cBINARY_SERIALIZATION_DIFFERS = false };
177  enum { cOTHER_SERIALIZATION_DIFFERS = true };
178};
179
180template <typename T1, typename T2>
181struct UnderlyingType<std::pair<T1, T2>>
182{
183  typedef std::pair<typename UnderlyingType<T1>::type, typename UnderlyingType<T2>::type> type;
184  enum { cREVERSE_CAST_VALID = UnderlyingType<T1>::cREVERSE_CAST_VALID && UnderlyingType<T2>::cREVERSE_CAST_VALID };
185  enum { cBINARY_SERIALIZATION_DIFFERS = UnderlyingType<T1>::cBINARY_SERIALIZATION_DIFFERS || UnderlyingType<T2>::cBINARY_SERIALIZATION_DIFFERS };
186  enum { cOTHER_SERIALIZATION_DIFFERS = UnderlyingType<T1>::cOTHER_SERIALIZATION_DIFFERS || UnderlyingType<T2>::cOTHER_SERIALIZATION_DIFFERS };
187};
188
189template <typename ... TArgs>
190struct UnderlyingType<std::tuple<TArgs ...>>
191{
192  typedef std::tuple<typename UnderlyingType<TArgs>::type...> type;
193  enum { cREVERSE_CAST_VALID = std::is_same < util::tIntegerSequence<UnderlyingType<TArgs>::cREVERSE_CAST_VALID...>, util::tIntegerSequence < true || UnderlyingType<TArgs>::cREVERSE_CAST_VALID... >>::value };
194  enum { cBINARY_SERIALIZATION_DIFFERS = !std::is_same < util::tIntegerSequence<UnderlyingType<TArgs>::cBINARY_SERIALIZATION_DIFFERS...>, util::tIntegerSequence < false && UnderlyingType<TArgs>::cBINARY_SERIALIZATION_DIFFERS... >>::value };
195  enum { cOTHER_SERIALIZATION_DIFFERS = !std::is_same < util::tIntegerSequence<UnderlyingType<TArgs>::cOTHER_SERIALIZATION_DIFFERS...>, util::tIntegerSequence < false && UnderlyingType<TArgs>::cOTHER_SERIALIZATION_DIFFERS... >>::value };
196};
197
198
199
200/*!
201 * Type trait that defines whether an object of type T can be safely deep-copied
202 * using memcpy and whether equality can be tested using memcmp.
203 *
204 * Should the default implementation be inadequate for some type T, it needs to be specialized.
205 */
206template <typename T>
207struct SupportsBitwiseCopy
208{
209  // std::is_trivially_destructible<T> is a heuristic. However, I have never encountered a type where this is invalid.
210  enum { value = (std::is_trivially_destructible<T>::value && (!std::has_virtual_destructor<T>::value) && (!std::is_polymorphic<T>::value)) ||
211                 std::conditional < !std::is_same<typename UnderlyingType<T>::type, T>::value, SupportsBitwiseCopy<typename UnderlyingType<T>::type>, std::false_type >::type::value
212       };
213};
214template <typename T, size_t N>
215struct SupportsBitwiseCopy<std::array<T, N>>
216{
217  enum { value = SupportsBitwiseCopy<T>::value };
218};
219template <typename T1, typename T2>
220struct SupportsBitwiseCopy<std::pair<T1, T2>>
221{
222  enum { value = SupportsBitwiseCopy<T1>::value && SupportsBitwiseCopy<T2>::value };
223};
224template <typename ... TArgs>
225struct SupportsBitwiseCopy<std::tuple<TArgs ...>>
226{
227  enum { value = std::is_same < util::tIntegerSequence<SupportsBitwiseCopy<TArgs>::value...>, util::tIntegerSequence < true || SupportsBitwiseCopy<TArgs>::value... >>::value };
228};
229
230
231/*!
232 * Type trait that defines whether an object of default-constructing an object of type T is equivalent
233 * to zeroing the memory it occupies.
234 *
235 * Should the default implementation be inadequate for some type T, it needs to be specialized.
236 */
237template <typename T>
238struct IsDefaultConstructionZeroMemory
239{
240  enum { value = SupportsBitwiseCopy<T>::value && (!std::is_enum<T>::value) };
241};
242template <typename T, size_t N>
243struct IsDefaultConstructionZeroMemory<std::array<T, N>>
244{
245  enum { value = IsDefaultConstructionZeroMemory<T>::value };
246};
247template <typename T1, typename T2>
248struct IsDefaultConstructionZeroMemory<std::pair<T1, T2>>
249{
250  enum { value = IsDefaultConstructionZeroMemory<T1>::value && IsDefaultConstructionZeroMemory<T2>::value };
251};
252template <typename ... TArgs>
253struct IsDefaultConstructionZeroMemory<std::tuple<TArgs ...>>
254{
255  enum { value = std::is_same < util::tIntegerSequence<IsDefaultConstructionZeroMemory<TArgs>::value...>, util::tIntegerSequence < true || IsDefaultConstructionZeroMemory<TArgs>::value... >>::value };
256};
257
258
259/*!
260 * Type trait that defines the rrlib_rtti name of a type.
261 * Template can be specialized for types in order to give them other names
262 * (possibly because they are more readable - or to retain backward-compatibility).
263 * Notably, a name can also be specified in the tDataType() constructor.
264 * This type trait, however, is useful for defining default names for templates.
265 *
266 * To assign additional secondary type names, value may also be a tGetTypenamesFunction
267 */
268template <typename T>
269struct TypeName
270{
271  enum { cTYPE_DEFINED_IN_RRLIB_RTTI_WITH_NONSTANDARD_NAME = (std::is_integral<T>::value || std::is_same<T, std::string>::value || std::is_same<T, rrlib::time::tDuration>::value || std::is_same<T, rrlib::time::tTimestamp>::value) && (!std::is_same<T, bool>::value) };
272
273  static constexpr tGetTypenameFunction value = cTYPE_DEFINED_IN_RRLIB_RTTI_WITH_NONSTANDARD_NAME ? &detail::tTypeInfo::GetTypeNameDefinedInRRLibRtti : &detail::tTypeInfo::GetDefaultTypeName;
274};
275
276/*!
277 * This trait defines which other types/conversion operations should be registered (if they have not been already)
278 * when a tDataType<T> object is created.
279 */
280template <typename T>
281struct AutoRegister
282{
283  static constexpr int Register()
284  {
285    return 0;
286  }
287};
288
289
290/*! Type trait that returns whether type T is a std::vector */
291template <typename T>
292struct IsStdVector
293{
294  enum { value = false };
295};
296template <typename T>
297struct IsStdVector<std::vector<T>>
298{
299  enum { value = true };
300};
301
302/*! Type trait that returns whether type T is a std::array */
303template <typename T>
304using IsStdArray = serialization::IsStdArray<T>;
305
306/*! Type trait that returns whether type T is an EnumBaseFlags type */
307template <typename T>
308struct IsEnumBasedFlags
309{
310  enum { value = false };
311};
312template <typename TFlag, typename TStorage>
313struct IsEnumBasedFlags<rrlib::util::tEnumBasedFlags<TFlag, TStorage>>
314{
315  enum { value = true };
316};
317
318/*! Type trait that returns whether type T is a std::pair */
319template <typename T>
320struct IsStdPair
321{
322  enum { value = false };
323};
324template <typename T1, typename T2>
325struct IsStdPair<std::pair<T1, T2>>
326{
327  enum { value = true };
328};
329
330/*! Type trait that returns whether type T is a std::tuple */
331template <typename T>
332struct IsStdTuple
333{
334  enum { value = false };
335};
336template <typename ... TArgs>
337struct IsStdTuple<std::tuple<TArgs ...>>
338{
339  enum { value = true };
340};
341
342
343/*! Trait to obtain type classifcation for type T */
344template <typename T>
345struct TypeClassification
346{
347  static const tTypeClassification value = IsStdArray<T>::value ? tTypeClassification::ARRAY :
348      (IsStdVector<T>::value ? tTypeClassification::LIST :
349       (IsStdPair<T>::value ? tTypeClassification::PAIR :
350        (IsStdTuple<T>::value ? tTypeClassification::TUPLE :
351         (std::is_integral<T>::value ? tTypeClassification::INTEGRAL :
352          (IsEnumBasedFlags<T>::value ? tTypeClassification::ENUM_BASED_FLAGS :
353           tTypeClassification::OTHER_DATA_TYPE)))));
354};
355
356/*!
357 * Type trait that determines whether std::vector<T> is automatically registered
358 * when a data type T is registered.
359 */
360template <typename T>
361struct AutoRegisterVectorType
362{
363  enum { value = (!serialization::IsSerializableContainer<T>::value) && (!IsStdTuple<T>::value) && (std::is_move_constructible<T>::value || std::is_copy_constructible<T>::value || std::is_move_assignable<T>::value || std::is_copy_assignable<T>::value) };
364};
365
366namespace trait_flags
367{
368
369// Bits for different traits (bytes 2 and 3 are sent to connection partners)
370static const int cIS_LIST_TYPE = 1;                          // position 1 - so that (flags & 1) is index in uid list
371static const int cSERIALIZATION_FUNCTION_OFFSET_BITS = 0x7E; // offset of serialization operation function pointers (flags & cSERIALIZATION_OFFSET_BITS is offset from tTypeInfo pointer)
372static const int cBINARY_OPERATION_FUNCTION_POINTERS = 0x80;
373
374static const int cIS_BINARY_SERIALIZABLE = 1 << 8;
375static const int cIS_STRING_SERIALIZABLE = 1 << 9;
376static const int cIS_XML_SERIALIZABLE = 1 << 10;
377static const int cIS_ENUM = 1 << 11;
378
379static const int cTYPE_CLASSIFICATION_BITS = 0xF << 12;
380
381static const int cHAS_UNDERLYING_TYPE = 1 << 16;
382static const int cIS_CAST_TO_UNDERLYING_TYPE_IMPLICIT = 1 << 17;
383static const int cIS_REINTERPRET_CAST_FROM_UNDERLYING_TYPE_VALID = 1 << 18;
384static const int cIS_CAST_FROM_UNDERLYING_TYPE_IMPLICIT = 1 << 19;
385static const int cIS_UNDERLYING_TYPE_BINARY_SERIALIZATION_DIFFERENT = 1 << 20;
386static const int cSUPPORTS_BITWISE_COPY = 1 << 21;
387
388static const int cHAS_TRIVIAL_DESTRUCTOR = 1 << 22;
389
390static const int cHAS_VIRTUAL_DESTRUCTOR = 1 << 24;
391static const int cIS_DEFAULT_CONSTRUCTION_ZERO_MEMORY = 1 << 25;
392
393} // namespace
394
395/*!
396 * Stores various type traits determined at compile time to bit vector
397 * so that traits are available at runtime.
398 *
399 * (Implementation note: We use constants (no bitset objects etc.) to
400 *  ensure everything is calculated at compile time)
401 */
402template <typename T>
403struct TypeTraitsVector
404{
405  enum { cHAS_DIFFERENT_UNDERLYING_TYPE = !std::is_same<typename UnderlyingType<T>::type, T>::value };
406  enum { cSERIALIZATION_FUNCTION_OFFSET = sizeof(detail::tTypeInfo) + (SupportsBitwiseCopy<T>::value && IsDefaultConstructionZeroMemory<T>::value ? 0 : sizeof(tBinaryOperations)) + (IsStdVector<T>::value ? sizeof(tBinaryOperationsVector) : 0) };
407  static_assert((cSERIALIZATION_FUNCTION_OFFSET & trait_flags::cSERIALIZATION_FUNCTION_OFFSET_BITS) == cSERIALIZATION_FUNCTION_OFFSET, "Invalid offset");
408
409  // Bit vector for type (the remaining flags are set in the code)
410  static const uint32_t value =
411    (IsStdVector<T>::value ? (trait_flags::cIS_LIST_TYPE) : 0) |
412    cSERIALIZATION_FUNCTION_OFFSET | // offset
413
414    (serialization::IsBinarySerializable<T>::value ? trait_flags::cIS_BINARY_SERIALIZABLE : 0) |
415    (serialization::IsStringSerializable<T>::value ? trait_flags::cIS_STRING_SERIALIZABLE : 0) |
416    (serialization::IsXMLSerializable<T>::value ? trait_flags::cIS_XML_SERIALIZABLE : 0) |
417
418    (std::is_enum<T>::value ? trait_flags::cIS_ENUM : 0) |
419    static_cast<uint>(TypeClassification<T>::value) |
420
421    (cHAS_DIFFERENT_UNDERLYING_TYPE ? trait_flags::cHAS_UNDERLYING_TYPE : 0) |
422    (cHAS_DIFFERENT_UNDERLYING_TYPE && IsImplicitlyConvertible<T, typename UnderlyingType<T>::type>::value ? trait_flags::cIS_CAST_TO_UNDERLYING_TYPE_IMPLICIT : 0) |
423    (cHAS_DIFFERENT_UNDERLYING_TYPE && UnderlyingType<T>::cREVERSE_CAST_VALID ? trait_flags::cIS_REINTERPRET_CAST_FROM_UNDERLYING_TYPE_VALID : 0) |
424    (cHAS_DIFFERENT_UNDERLYING_TYPE && IsImplicitlyConvertible<typename UnderlyingType<T>::type, T>::value ? trait_flags::cIS_CAST_FROM_UNDERLYING_TYPE_IMPLICIT : 0) |
425    (cHAS_DIFFERENT_UNDERLYING_TYPE && UnderlyingType<T>::cBINARY_SERIALIZATION_DIFFERS ? trait_flags::cIS_UNDERLYING_TYPE_BINARY_SERIALIZATION_DIFFERENT : 0) |
426    (SupportsBitwiseCopy<T>::value ? trait_flags::cSUPPORTS_BITWISE_COPY : 0) |
427
428    (std::has_virtual_destructor<T>::value ? trait_flags::cHAS_VIRTUAL_DESTRUCTOR : 0) |
429    (std::is_trivially_destructible<T>::value ? trait_flags::cHAS_TRIVIAL_DESTRUCTOR : 0) |
430    (IsDefaultConstructionZeroMemory<T>::value ? trait_flags::cIS_DEFAULT_CONSTRUCTION_ZERO_MEMORY : 0)
431    ;
432
433  // sanity check of type traits for type T
434  static_assert((!SupportsBitwiseCopy<T>::value) || (!std::has_virtual_destructor<T>::value), "This would copy/compare vtable pointers");
435  static_assert(sizeof(T) == sizeof(typename UnderlyingType<T>::type), "Types need the same memory layout");
436};
437
438/*!
439 * This type trait is used to determine whether a type supports operator '<' .
440 */
441template <typename T>
442struct HasLessThanOperator
443{
444  template <typename U>
445  static U &Make();
446
447  template <typename U = T>
448  static int16_t Test(decltype(Make<U>() < Make<U>()));
449
450  static int32_t Test(...);
451
452  enum { value = sizeof(Test(true)) == sizeof(int16_t) };
453};
454
455/*!
456 * This type trait is used to determine whether a type supports operator '==' .
457 */
458template <typename T>
459struct HasEqualToOperator
460{
461  template <typename U>
462  static U &Make();
463
464  template <typename U = T>
465  static int16_t Test(decltype(Make<U>() == Make<U>()));
466
467  static int32_t Test(...);
468
469  enum { value = sizeof(Test(true)) == sizeof(int16_t) };
470};
471template <typename T>
472struct HasEqualToOperator<std::vector<T>>
473{
474  enum { value = HasEqualToOperator<T>::value };
475};
476
477/*!
478 * Type trait to get 'normalized' type for type T.
479 * It is used to reduce the number of int types to a platform-independent subset.
480 * 'type' is usually T - unless this is e.g. a 'long int' or 'char' type.
481 */
482template <typename T>
483struct NormalizedType
484{
485  typedef typename std::conditional<std::is_integral<T>::value, typename detail::NormalizedIntegerType<sizeof(T), std::is_unsigned<T>::value>::type, T>::type type;
486};
487template <typename T>
488struct NormalizedType<std::vector<T>>
489{
490  typedef std::vector<typename NormalizedType<T>::type> type;
491};
492template <typename T, size_t N>
493struct NormalizedType<std::array<T, N>>
494{
495  typedef std::array<typename NormalizedType<T>::type, N> type;
496};
497template <>
498struct NormalizedType<bool>
499{
500  typedef bool type;
501};
502template <>
503struct NormalizedType<void>
504{
505  typedef void type;
506};
507
508
509/*!
510 * Type trait to determine whether type T is 'normalized'
511 */
512template <typename T>
513struct IsNormalizedType
514{
515  enum { value = std::is_same<T, typename NormalizedType<T>::type>::value };
516};
517
518/*!
519 * Type traits to determine element type if T is STL container or rrlib::util::tEnumBasedFlags - otherwise void
520 */
521template <typename T>
522struct ElementType
523{
524  typedef typename serialization::IsSerializableContainer<T>::tValue type;
525};
526
527template <typename TFlag, typename TStorage>
528struct ElementType<rrlib::util::tEnumBasedFlags<TFlag, TStorage>>
529{
530  typedef TFlag type;
531};
532
533//----------------------------------------------------------------------
534// End of namespace declaration
535//----------------------------------------------------------------------
536}
537}
538
539#endif
Note: See TracBrowser for help on using the repository browser.