1 /*========================================================================= 2 * 3 * Copyright Insight Software Consortium 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0.txt 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 *=========================================================================*/ 18 #ifndef itkPromoteType_h 19 #define itkPromoteType_h 20 21 #include "itkMacro.h" 22 23 // Simplification of boost::common_type 24 namespace itk { 25 26 /// \cond HIDE_META_PROGRAMMING 27 namespace mpl { 28 29 namespace Details { 30 31 /** Helper class to implement \c itk::PromoteType<>. 32 * This struct is meant to be specialized with \c ITK_ASSOCIATE macros for the 33 * primitive types, or by the end-developper in order to support overloads. 34 * \ingroup MetaProgrammingLibrary 35 * \ingroup ITKCommon 36 */ 37 template <int N, typename TA, typename TB> struct SizeToType; 38 39 /** Helper class to implement \c itk::PromoteType<>. 40 * \ingroup MetaProgrammingLibrary 41 * \ingroup ITKCommon 42 */ 43 template <int N> struct Identity { typedef char Type[N]; }; 44 45 /** Helper macro to implement \c itk::PromoteType<>. 46 * This macros helps specializing \c SizeToType<> for any pair of type. 47 * \ingroup MetaProgrammingLibrary 48 * \ingroup ITKCommon 49 */ 50 #define ITK_ASSOCIATE(N, Typed)\ 51 template <typename TA, typename TB> struct SizeToType<N,TA,TB> { using Type = Typed; }; 52 53 ITK_ASSOCIATE(1, TA); 54 ITK_ASSOCIATE(2, TB); 55 56 ITK_ASSOCIATE(3, short); 57 ITK_ASSOCIATE(4, unsigned short); 58 ITK_ASSOCIATE(5, int); 59 ITK_ASSOCIATE(6, unsigned int); 60 ITK_ASSOCIATE(7, long); 61 ITK_ASSOCIATE(8, unsigned long); 62 ITK_ASSOCIATE(9, long long); 63 ITK_ASSOCIATE(10, unsigned long long); 64 ITK_ASSOCIATE(11, float); 65 ITK_ASSOCIATE(12, double); 66 ITK_ASSOCIATE(13, long double); 67 #undef ITK_ASSOCIATE 68 } // Details namespace 69 70 /** Helper class to deduce, in C++98, the resulting type of an operation between two input types. 71 * \tparam TA Input type 1 72 * \tparam TB Input type 2 73 * \return \c Type the resulting type compatible with \c TA and \c TB. 74 * 75 * In order to support user defined type, specialize \c 76 * itk::PromoteType<> in consequence. For instance, to support type promotion 77 * between \c std::complex<>, write: 78 \code 79 namespace itk { 80 template <typename TA, typename TB> 81 struct PromoteType<std::complex<TA>, std::complex<TB> > { 82 using Type = std::complex<typename PromoteType<TA,TB>::Type>; 83 }; 84 } 85 \endcode 86 * 87 * \ingroup MetaProgrammingLibrary 88 * \ingroup ITKCommon 89 */ 90 template <typename TA, typename TB> struct PromoteType 91 { 92 static TA a; 93 static TB b; 94 95 // Aimed at supporting overloads 96 template <typename T> static Details::Identity<1>::Type& Check(typename Details::SizeToType<1, TA, TB>::Type, T); 97 template <typename T> static Details::Identity<2>::Type& Check(typename Details::SizeToType<2, TA, TB>::Type, T); 98 99 // Common numeric types 100 static Details::Identity<3 >::Type& Check(typename Details::SizeToType<3, TA, TB>::Type, int); 101 static Details::Identity<4 >::Type& Check(typename Details::SizeToType<4, TA, TB>::Type, int); 102 static Details::Identity<5 >::Type& Check(typename Details::SizeToType<5, TA, TB>::Type, int); 103 static Details::Identity<6 >::Type& Check(typename Details::SizeToType<6, TA, TB>::Type, int); 104 static Details::Identity<7 >::Type& Check(typename Details::SizeToType<7, TA, TB>::Type, int); 105 static Details::Identity<8 >::Type& Check(typename Details::SizeToType<8, TA, TB>::Type, int); 106 static Details::Identity<9 >::Type& Check(typename Details::SizeToType<9, TA, TB>::Type, int); 107 static Details::Identity<10>::Type& Check(typename Details::SizeToType<10, TA, TB>::Type, int); 108 static Details::Identity<11>::Type& Check(typename Details::SizeToType<11, TA, TB>::Type, int); 109 static Details::Identity<12>::Type& Check(typename Details::SizeToType<12, TA, TB>::Type, int); 110 static Details::Identity<13>::Type& Check(typename Details::SizeToType<13, TA, TB>::Type, int); 111 public: 112 /** Type result of operations between \c TA and \c TB. 113 * \internal 114 * We let the compiler deduce the type resulting of the operation `a+b`. As 115 * the standard says (see the extract in the test file itkPromoteType.cxx), 116 * <em>«arithmetic operators do not accept types smaller than int as 117 * arguments»</em>, that's why \c ITK_ASSOCIATE() is not used with \c char 118 * nor \c short. 119 * 120 * Then, we let the compiler choose the right \c Check() overload. From here, 121 * it'll know which \c Detail::Identity<> specialization is returned. 122 * \c sizeof can thus be used to extract the size of the specialization. 123 * 124 * Finally, \c Details::SizeToType<> returns the type that holds the result 125 * of `a+b`. 126 */ 127 using Type = typename Details::SizeToType<sizeof Check(a+b, 0), TA, TB>::Type; 128 }; 129 } // end namespace mpl 130 131 /// \endcond 132 } // end namespace itk 133 134 #endif // itkPromoteType_h 135