source: rrlib_rtti/type_traits.h @ 113:19aca1477e99

17.03
Last change on this file since 113:19aca1477e99 was 113:19aca1477e99, checked in by Max Reichardt <max.reichardt@…>, 18 months ago

Adds 'INHERITS_UNDERLYING_TYPE_ELEMENT_ACCESS_OPERATIONS' flag to tUnderlyingType type trait. This allows to use built-in element access operation '[]' for e.g. rrlib_math vectors also.

File size: 21.9 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  /*! Optional - if underlying type is e.g. std::array, will inherit element access operations from it (as defined in rrlib_rtti_conversion/defined_conversions.h) */
153  enum { cINHERITS_ELEMENT_ACCESS_CONVERSION_OPERATIONS = false };
154};
155
156template <typename T>
157struct UnderlyingType<std::vector<T>>
158{
159  typedef std::vector<typename UnderlyingType<T>::type> type;
160  enum { cREVERSE_CAST_VALID = UnderlyingType<T>::cREVERSE_CAST_VALID };
161  enum { cBINARY_SERIALIZATION_DIFFERS = UnderlyingType<T>::cBINARY_SERIALIZATION_DIFFERS };
162  enum { cOTHER_SERIALIZATION_DIFFERS = UnderlyingType<T>::cOTHER_SERIALIZATION_DIFFERS };
163};
164
165template <typename T, size_t N>
166struct UnderlyingType<std::array<T, N>>
167{
168  typedef std::array<typename UnderlyingType<T>::type, N> type;
169  enum { cREVERSE_CAST_VALID = UnderlyingType<T>::cREVERSE_CAST_VALID };
170  enum { cBINARY_SERIALIZATION_DIFFERS = UnderlyingType<T>::cBINARY_SERIALIZATION_DIFFERS };
171  enum { cOTHER_SERIALIZATION_DIFFERS = UnderlyingType<T>::cOTHER_SERIALIZATION_DIFFERS };
172};
173
174template <typename TFlag, typename TStorage>
175struct UnderlyingType<rrlib::util::tEnumBasedFlags<TFlag, TStorage>>
176{
177  typedef TStorage type;
178  enum { cREVERSE_CAST_VALID = true };
179  enum { cBINARY_SERIALIZATION_DIFFERS = false };
180  enum { cOTHER_SERIALIZATION_DIFFERS = true };
181};
182
183template <typename T1, typename T2>
184struct UnderlyingType<std::pair<T1, T2>>
185{
186  typedef std::pair<typename UnderlyingType<T1>::type, typename UnderlyingType<T2>::type> type;
187  enum { cREVERSE_CAST_VALID = UnderlyingType<T1>::cREVERSE_CAST_VALID && UnderlyingType<T2>::cREVERSE_CAST_VALID };
188  enum { cBINARY_SERIALIZATION_DIFFERS = UnderlyingType<T1>::cBINARY_SERIALIZATION_DIFFERS || UnderlyingType<T2>::cBINARY_SERIALIZATION_DIFFERS };
189  enum { cOTHER_SERIALIZATION_DIFFERS = UnderlyingType<T1>::cOTHER_SERIALIZATION_DIFFERS || UnderlyingType<T2>::cOTHER_SERIALIZATION_DIFFERS };
190};
191
192template <typename ... TArgs>
193struct UnderlyingType<std::tuple<TArgs ...>>
194{
195  typedef std::tuple<typename UnderlyingType<TArgs>::type...> type;
196  enum { cREVERSE_CAST_VALID = std::is_same < util::tIntegerSequence<UnderlyingType<TArgs>::cREVERSE_CAST_VALID...>, util::tIntegerSequence < true || UnderlyingType<TArgs>::cREVERSE_CAST_VALID... >>::value };
197  enum { cBINARY_SERIALIZATION_DIFFERS = !std::is_same < util::tIntegerSequence<UnderlyingType<TArgs>::cBINARY_SERIALIZATION_DIFFERS...>, util::tIntegerSequence < false && UnderlyingType<TArgs>::cBINARY_SERIALIZATION_DIFFERS... >>::value };
198  enum { cOTHER_SERIALIZATION_DIFFERS = !std::is_same < util::tIntegerSequence<UnderlyingType<TArgs>::cOTHER_SERIALIZATION_DIFFERS...>, util::tIntegerSequence < false && UnderlyingType<TArgs>::cOTHER_SERIALIZATION_DIFFERS... >>::value };
199};
200
201
202
203/*!
204 * Type trait that defines whether an object of type T can be safely deep-copied
205 * using memcpy and whether equality can be tested using memcmp.
206 *
207 * Should the default implementation be inadequate for some type T, it needs to be specialized.
208 */
209template <typename T>
210struct SupportsBitwiseCopy
211{
212  // std::is_trivially_destructible<T> is a heuristic. However, I have never encountered a type where this is invalid.
213  enum { value = (std::is_trivially_destructible<T>::value && (!std::has_virtual_destructor<T>::value) && (!std::is_polymorphic<T>::value)) ||
214                 std::conditional < !std::is_same<typename UnderlyingType<T>::type, T>::value, SupportsBitwiseCopy<typename UnderlyingType<T>::type>, std::false_type >::type::value
215       };
216};
217template <typename T, size_t N>
218struct SupportsBitwiseCopy<std::array<T, N>>
219{
220  enum { value = SupportsBitwiseCopy<T>::value };
221};
222template <typename T1, typename T2>
223struct SupportsBitwiseCopy<std::pair<T1, T2>>
224{
225  enum { value = SupportsBitwiseCopy<T1>::value && SupportsBitwiseCopy<T2>::value };
226};
227template <typename ... TArgs>
228struct SupportsBitwiseCopy<std::tuple<TArgs ...>>
229{
230  enum { value = std::is_same < util::tIntegerSequence<SupportsBitwiseCopy<TArgs>::value...>, util::tIntegerSequence < true || SupportsBitwiseCopy<TArgs>::value... >>::value };
231};
232
233
234/*!
235 * Type trait that defines whether an object of default-constructing an object of type T is equivalent
236 * to zeroing the memory it occupies.
237 *
238 * Should the default implementation be inadequate for some type T, it needs to be specialized.
239 */
240template <typename T>
241struct IsDefaultConstructionZeroMemory
242{
243  enum { value = SupportsBitwiseCopy<T>::value && (!std::is_enum<T>::value) };
244};
245template <typename T, size_t N>
246struct IsDefaultConstructionZeroMemory<std::array<T, N>>
247{
248  enum { value = IsDefaultConstructionZeroMemory<T>::value };
249};
250template <typename T1, typename T2>
251struct IsDefaultConstructionZeroMemory<std::pair<T1, T2>>
252{
253  enum { value = IsDefaultConstructionZeroMemory<T1>::value && IsDefaultConstructionZeroMemory<T2>::value };
254};
255template <typename ... TArgs>
256struct IsDefaultConstructionZeroMemory<std::tuple<TArgs ...>>
257{
258  enum { value = std::is_same < util::tIntegerSequence<IsDefaultConstructionZeroMemory<TArgs>::value...>, util::tIntegerSequence < true || IsDefaultConstructionZeroMemory<TArgs>::value... >>::value };
259};
260
261
262/*!
263 * Type trait that defines the rrlib_rtti name of a type.
264 * Template can be specialized for types in order to give them other names
265 * (possibly because they are more readable - or to retain backward-compatibility).
266 * Notably, a name can also be specified in the tDataType() constructor.
267 * This type trait, however, is useful for defining default names for templates.
268 *
269 * To assign additional secondary type names, value may also be a tGetTypenamesFunction
270 */
271template <typename T>
272struct TypeName
273{
274  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) };
275
276  static constexpr tGetTypenameFunction value = cTYPE_DEFINED_IN_RRLIB_RTTI_WITH_NONSTANDARD_NAME ? &detail::tTypeInfo::GetTypeNameDefinedInRRLibRtti : &detail::tTypeInfo::GetDefaultTypeName;
277};
278
279/*!
280 * This trait defines which other types/conversion operations should be registered (if they have not been already)
281 * when a tDataType<T> object is created.
282 */
283template <typename T>
284struct AutoRegister
285{
286  static constexpr int Register()
287  {
288    return 0;
289  }
290};
291
292
293/*! Type trait that returns whether type T is a std::vector */
294template <typename T>
295struct IsStdVector
296{
297  enum { value = false };
298};
299template <typename T>
300struct IsStdVector<std::vector<T>>
301{
302  enum { value = true };
303};
304
305/*! Type trait that returns whether type T is a std::array */
306template <typename T>
307using IsStdArray = serialization::IsStdArray<T>;
308
309/*! Type trait that returns whether type T is an EnumBaseFlags type */
310template <typename T>
311struct IsEnumBasedFlags
312{
313  enum { value = false };
314};
315template <typename TFlag, typename TStorage>
316struct IsEnumBasedFlags<rrlib::util::tEnumBasedFlags<TFlag, TStorage>>
317{
318  enum { value = true };
319};
320
321/*! Type trait that returns whether type T is a std::pair */
322template <typename T>
323struct IsStdPair
324{
325  enum { value = false };
326};
327template <typename T1, typename T2>
328struct IsStdPair<std::pair<T1, T2>>
329{
330  enum { value = true };
331};
332
333/*! Type trait that returns whether type T is a std::tuple */
334template <typename T>
335struct IsStdTuple
336{
337  enum { value = false };
338};
339template <typename ... TArgs>
340struct IsStdTuple<std::tuple<TArgs ...>>
341{
342  enum { value = true };
343};
344
345
346/*! Trait to obtain type classifcation for type T */
347template <typename T>
348struct TypeClassification
349{
350  static const tTypeClassification value = IsStdArray<T>::value ? tTypeClassification::ARRAY :
351      (IsStdVector<T>::value ? tTypeClassification::LIST :
352       (IsStdPair<T>::value ? tTypeClassification::PAIR :
353        (IsStdTuple<T>::value ? tTypeClassification::TUPLE :
354         (std::is_integral<T>::value ? tTypeClassification::INTEGRAL :
355          (IsEnumBasedFlags<T>::value ? tTypeClassification::ENUM_BASED_FLAGS :
356           tTypeClassification::OTHER_DATA_TYPE)))));
357};
358
359/*!
360 * Type trait that determines whether std::vector<T> is automatically registered
361 * when a data type T is registered.
362 */
363template <typename T>
364struct AutoRegisterVectorType
365{
366  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) };
367};
368
369namespace trait_flags
370{
371
372// Bits for different traits (bytes 2 and 3 are sent to connection partners)
373static const int cIS_LIST_TYPE = 1;                          // position 1 - so that (flags & 1) is index in uid list
374static const int cSERIALIZATION_FUNCTION_OFFSET_BITS = 0x7E; // offset of serialization operation function pointers (flags & cSERIALIZATION_OFFSET_BITS is offset from tTypeInfo pointer)
375static const int cBINARY_OPERATION_FUNCTION_POINTERS = 0x80;
376
377static const int cIS_BINARY_SERIALIZABLE = 1 << 8;
378static const int cIS_STRING_SERIALIZABLE = 1 << 9;
379static const int cIS_XML_SERIALIZABLE = 1 << 10;
380static const int cIS_ENUM = 1 << 11;
381
382static const int cTYPE_CLASSIFICATION_BITS = 0xF << 12;
383
384static const int cHAS_UNDERLYING_TYPE = 1 << 16;
385static const int cIS_CAST_TO_UNDERLYING_TYPE_IMPLICIT = 1 << 17;
386static const int cIS_REINTERPRET_CAST_FROM_UNDERLYING_TYPE_VALID = 1 << 18;
387static const int cIS_CAST_FROM_UNDERLYING_TYPE_IMPLICIT = 1 << 19;
388static const int cIS_UNDERLYING_TYPE_BINARY_SERIALIZATION_DIFFERENT = 1 << 20;
389static const int cSUPPORTS_BITWISE_COPY = 1 << 21;
390
391static const int cHAS_TRIVIAL_DESTRUCTOR = 1 << 22;
392static const int cINHERITS_UNDERLYING_TYPE_ELEMENT_ACCESS_OPERATIONS = 1 << 23;
393
394static const int cHAS_VIRTUAL_DESTRUCTOR = 1 << 24;
395static const int cIS_DEFAULT_CONSTRUCTION_ZERO_MEMORY = 1 << 25;
396
397} // namespace
398
399/*!
400 * Stores various type traits determined at compile time to bit vector
401 * so that traits are available at runtime.
402 *
403 * (Implementation note: We use constants (no bitset objects etc.) to
404 *  ensure everything is calculated at compile time)
405 */
406template <typename T>
407struct TypeTraitsVector
408{
409  enum { cHAS_DIFFERENT_UNDERLYING_TYPE = !std::is_same<typename UnderlyingType<T>::type, T>::value };
410  enum { cSERIALIZATION_FUNCTION_OFFSET = sizeof(detail::tTypeInfo) + (SupportsBitwiseCopy<T>::value && IsDefaultConstructionZeroMemory<T>::value ? 0 : sizeof(tBinaryOperations)) + (IsStdVector<T>::value ? sizeof(tBinaryOperationsVector) : 0) };
411  static_assert((cSERIALIZATION_FUNCTION_OFFSET & trait_flags::cSERIALIZATION_FUNCTION_OFFSET_BITS) == cSERIALIZATION_FUNCTION_OFFSET, "Invalid offset");
412
413  // Bit vector for type (the remaining flags are set in the code)
414  static const uint32_t value =
415    (IsStdVector<T>::value ? (trait_flags::cIS_LIST_TYPE) : 0) |
416    cSERIALIZATION_FUNCTION_OFFSET | // offset
417
418    (serialization::IsBinarySerializable<T>::value ? trait_flags::cIS_BINARY_SERIALIZABLE : 0) |
419    (serialization::IsStringSerializable<T>::value ? trait_flags::cIS_STRING_SERIALIZABLE : 0) |
420    (serialization::IsXMLSerializable<T>::value ? trait_flags::cIS_XML_SERIALIZABLE : 0) |
421
422    (std::is_enum<T>::value ? trait_flags::cIS_ENUM : 0) |
423    static_cast<uint>(TypeClassification<T>::value) |
424
425    (cHAS_DIFFERENT_UNDERLYING_TYPE ? trait_flags::cHAS_UNDERLYING_TYPE : 0) |
426    (cHAS_DIFFERENT_UNDERLYING_TYPE && IsImplicitlyConvertible<T, typename UnderlyingType<T>::type>::value ? trait_flags::cIS_CAST_TO_UNDERLYING_TYPE_IMPLICIT : 0) |
427    (cHAS_DIFFERENT_UNDERLYING_TYPE && UnderlyingType<T>::cREVERSE_CAST_VALID ? trait_flags::cIS_REINTERPRET_CAST_FROM_UNDERLYING_TYPE_VALID : 0) |
428    (cHAS_DIFFERENT_UNDERLYING_TYPE && IsImplicitlyConvertible<typename UnderlyingType<T>::type, T>::value ? trait_flags::cIS_CAST_FROM_UNDERLYING_TYPE_IMPLICIT : 0) |
429    (cHAS_DIFFERENT_UNDERLYING_TYPE && UnderlyingType<T>::cBINARY_SERIALIZATION_DIFFERS ? trait_flags::cIS_UNDERLYING_TYPE_BINARY_SERIALIZATION_DIFFERENT : 0) |
430    (SupportsBitwiseCopy<T>::value ? trait_flags::cSUPPORTS_BITWISE_COPY : 0) |
431
432    (std::has_virtual_destructor<T>::value ? trait_flags::cHAS_VIRTUAL_DESTRUCTOR : 0) |
433    (std::is_trivially_destructible<T>::value ? trait_flags::cHAS_TRIVIAL_DESTRUCTOR : 0) |
434    (IsDefaultConstructionZeroMemory<T>::value ? trait_flags::cIS_DEFAULT_CONSTRUCTION_ZERO_MEMORY : 0) |
435    (detail::InheritsUnderlyingTypeElementAccessOperations<T>::value ? trait_flags::cINHERITS_UNDERLYING_TYPE_ELEMENT_ACCESS_OPERATIONS : 0)
436    ;
437
438  // sanity check of type traits for type T
439  static_assert((!SupportsBitwiseCopy<T>::value) || (!std::has_virtual_destructor<T>::value), "This would copy/compare vtable pointers");
440  static_assert(sizeof(T) == sizeof(typename UnderlyingType<T>::type), "Types need the same memory layout");
441};
442
443/*!
444 * This type trait is used to determine whether a type supports operator '<' .
445 */
446template <typename T>
447struct HasLessThanOperator
448{
449  template <typename U>
450  static U &Make();
451
452  template <typename U = T>
453  static int16_t Test(decltype(Make<U>() < Make<U>()));
454
455  static int32_t Test(...);
456
457  enum { value = sizeof(Test(true)) == sizeof(int16_t) };
458};
459
460/*!
461 * This type trait is used to determine whether a type supports operator '==' .
462 */
463template <typename T>
464struct HasEqualToOperator
465{
466  template <typename U>
467  static U &Make();
468
469  template <typename U = T>
470  static int16_t Test(decltype(Make<U>() == Make<U>()));
471
472  static int32_t Test(...);
473
474  enum { value = sizeof(Test(true)) == sizeof(int16_t) };
475};
476template <typename T>
477struct HasEqualToOperator<std::vector<T>>
478{
479  enum { value = HasEqualToOperator<T>::value };
480};
481
482/*!
483 * Type trait to get 'normalized' type for type T.
484 * It is used to reduce the number of int types to a platform-independent subset.
485 * 'type' is usually T - unless this is e.g. a 'long int' or 'char' type.
486 */
487template <typename T>
488struct NormalizedType
489{
490  typedef typename std::conditional<std::is_integral<T>::value, typename detail::NormalizedIntegerType<sizeof(T), std::is_unsigned<T>::value>::type, T>::type type;
491};
492template <typename T>
493struct NormalizedType<std::vector<T>>
494{
495  typedef std::vector<typename NormalizedType<T>::type> type;
496};
497template <typename T, size_t N>
498struct NormalizedType<std::array<T, N>>
499{
500  typedef std::array<typename NormalizedType<T>::type, N> type;
501};
502template <>
503struct NormalizedType<bool>
504{
505  typedef bool type;
506};
507template <>
508struct NormalizedType<void>
509{
510  typedef void type;
511};
512
513
514/*!
515 * Type trait to determine whether type T is 'normalized'
516 */
517template <typename T>
518struct IsNormalizedType
519{
520  enum { value = std::is_same<T, typename NormalizedType<T>::type>::value };
521};
522
523/*!
524 * Type traits to determine element type if T is STL container or rrlib::util::tEnumBasedFlags - otherwise void
525 */
526template <typename T>
527struct ElementType
528{
529  typedef typename serialization::IsSerializableContainer<T>::tValue type;
530};
531
532template <typename TFlag, typename TStorage>
533struct ElementType<rrlib::util::tEnumBasedFlags<TFlag, TStorage>>
534{
535  typedef TFlag type;
536};
537
538//----------------------------------------------------------------------
539// End of namespace declaration
540//----------------------------------------------------------------------
541}
542}
543
544#endif
Note: See TracBrowser for help on using the repository browser.