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