blob: b3f2bd0838e8eed4451b087e79aa7370472acc1e [file] [log] [blame]
Jeff Thompsona28eed82013-08-22 16:21:10 -07001/*******************************************************************************
2 * boost/type_traits/detail/common_type_imp.hpp
3 *
4 * Copyright 2010, Jeffrey Hellrung.
5 * Distributed under the Boost Software License, Version 1.0. (See accompanying
6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 *
8 * struct ndnboost::common_type<T,U>
9 *
10 * common_type<T,U>::type is the type of the expression
11 * b() ? x() : y()
12 * where b() returns a bool, x() has return type T, and y() has return type U.
13 * See
14 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm#common_type
15 *
16 * Note that this evaluates to void if one or both of T and U is void.
17 ******************************************************************************/
18
19#ifndef BOOST_TYPE_TRAITS_DETAIL_COMMON_TYPE_IMP_HPP
20#define BOOST_TYPE_TRAITS_DETAIL_COMMON_TYPE_IMP_HPP
21
22#include <cstddef>
23
24#include <ndnboost/mpl/assert.hpp>
25#include <ndnboost/mpl/at.hpp>
26#include <ndnboost/mpl/begin_end.hpp>
27#include <ndnboost/mpl/contains.hpp>
28#include <ndnboost/mpl/copy.hpp>
29#include <ndnboost/mpl/deref.hpp>
30#include <ndnboost/mpl/eval_if.hpp>
31#include <ndnboost/mpl/if.hpp>
32#include <ndnboost/mpl/inserter.hpp>
33#include <ndnboost/mpl/next.hpp>
34#include <ndnboost/mpl/or.hpp>
35#include <ndnboost/mpl/placeholders.hpp>
36#include <ndnboost/mpl/push_back.hpp>
37#include <ndnboost/mpl/size.hpp>
38#include <ndnboost/mpl/vector/vector0.hpp>
39#include <ndnboost/mpl/vector/vector10.hpp>
40#include <ndnboost/type_traits/integral_constant.hpp>
41#include <ndnboost/type_traits/is_enum.hpp>
42#include <ndnboost/type_traits/is_integral.hpp>
43#include <ndnboost/type_traits/make_signed.hpp>
44#include <ndnboost/type_traits/make_unsigned.hpp>
45#include <ndnboost/type_traits/remove_cv.hpp>
46#include <ndnboost/type_traits/remove_reference.hpp>
47#include <ndnboost/utility/declval.hpp>
48
49namespace ndnboost
50{
51
52namespace detail_type_traits_common_type
53{
54
55/*******************************************************************************
56 * struct propagate_cv< From, To >
57 *
58 * This metafunction propagates cv-qualifiers on type From to type To.
59 ******************************************************************************/
60
61template< class From, class To >
62struct propagate_cv
63{ typedef To type; };
64template< class From, class To >
65struct propagate_cv< const From, To >
66{ typedef To const type; };
67template< class From, class To >
68struct propagate_cv< volatile From, To >
69{ typedef To volatile type; };
70template< class From, class To >
71struct propagate_cv< const volatile From, To >
72{ typedef To const volatile type; };
73
74/*******************************************************************************
75 * struct is_integral_or_enum<T>
76 *
77 * This metafunction determines if T is an integral type which can be made
78 * signed or unsigned.
79 ******************************************************************************/
80
81template< class T >
82struct is_integral_or_enum
83 : public mpl::or_< is_integral<T>, is_enum<T> >
84{ };
85template<>
86struct is_integral_or_enum< bool >
87 : public false_type
88{ };
89
90/*******************************************************************************
91 * struct make_unsigned_soft<T>
92 * struct make_signed_soft<T>
93 *
94 * These metafunction are identical to make_unsigned and make_signed,
95 * respectively, except for special-casing bool.
96 ******************************************************************************/
97
98template< class T >
99struct make_unsigned_soft
100 : public make_unsigned<T>
101{ };
102template<>
103struct make_unsigned_soft< bool >
104{ typedef bool type; };
105
106template< class T >
107struct make_signed_soft
108 : public make_signed<T>
109{ };
110template<>
111struct make_signed_soft< bool >
112{ typedef bool type; };
113
114/*******************************************************************************
115 * struct sizeof_t<N>
116 * typedef ... yes_type
117 * typedef ... no_type
118 *
119 * These types are integral players in the use of the "sizeof trick", i.e., we
120 * can distinguish overload selection by inspecting the size of the return type
121 * of the overload.
122 ******************************************************************************/
123
124template< std::size_t N > struct sizeof_t { char _dummy[N]; };
125typedef sizeof_t<1> yes_type;
126typedef sizeof_t<2> no_type;
127BOOST_MPL_ASSERT_RELATION( sizeof( yes_type ), ==, 1 );
128BOOST_MPL_ASSERT_RELATION( sizeof( no_type ), ==, 2 );
129
130/*******************************************************************************
131 * rvalue_test(T&) -> no_type
132 * rvalue_test(...) -> yes_type
133 *
134 * These overloads are used to determine the rvalue-ness of an expression.
135 ******************************************************************************/
136
137template< class T > no_type rvalue_test(T&);
138yes_type rvalue_test(...);
139
140/*******************************************************************************
141 * struct conversion_test_overloads< Sequence >
142 *
143 * This struct has multiple overloads of the static member function apply, each
144 * one taking a single parameter of a type within the Boost.MPL sequence
145 * Sequence. Each such apply overload has a return type with sizeof equal to
146 * one plus the index of the parameter type within Sequence. Thus, we can
147 * deduce the type T of an expression as long as we can generate a finite set of
148 * candidate types containing T via these apply overloads and the "sizeof
149 * trick".
150 ******************************************************************************/
151
152template< class First, class Last, std::size_t Index >
153struct conversion_test_overloads_iterate
154 : public conversion_test_overloads_iterate<
155 typename mpl::next< First >::type, Last, Index + 1
156 >
157{
158 using conversion_test_overloads_iterate<
159 typename mpl::next< First >::type, Last, Index + 1
160 >::apply;
161 static sizeof_t< Index + 1 >
162 apply(typename mpl::deref< First >::type);
163};
164
165template< class Last, std::size_t Index >
166struct conversion_test_overloads_iterate< Last, Last, Index >
167{ static sizeof_t< Index + 1 > apply(...); };
168
169template< class Sequence >
170struct conversion_test_overloads
171 : public conversion_test_overloads_iterate<
172 typename mpl::begin< Sequence >::type,
173 typename mpl::end< Sequence >::type,
174 0
175 >
176{ };
177
178/*******************************************************************************
179 * struct select< Sequence, Index >
180 *
181 * select is synonymous with mpl::at_c unless Index equals the size of the
182 * Boost.MPL Sequence, in which case this evaluates to void.
183 ******************************************************************************/
184
185template<
186 class Sequence, int Index,
187 int N = mpl::size< Sequence >::value
188>
189struct select
190 : public mpl::at_c< Sequence, Index >
191{ };
192template< class Sequence, int N >
193struct select< Sequence, N, N >
194{ typedef void type; };
195
196/*******************************************************************************
197 * class deduce_common_type< T, U, NominalCandidates >
198 * struct nominal_candidates<T,U>
199 * struct common_type_dispatch_on_rvalueness<T,U>
200 * struct common_type_impl<T,U>
201 *
202 * These classes and structs implement the logic behind common_type, which goes
203 * roughly as follows. Let C be the type of the conditional expression
204 * declval< bool >() ? declval<T>() : declval<U>()
205 * if C is an rvalue, then:
206 * let T' and U' be T and U stripped of reference- and cv-qualifiers
207 * if T' and U' are pointer types, say, T' = V* and U' = W*, then:
208 * define the set of NominalCandidates to be
209 * { V*, W*, V'*, W'* }
210 * where V' is V with whatever cv-qualifiers are on W, and W' is W
211 * with whatever cv-qualifiers are on V
212 * else if T' and U' are both integral or enum types, then:
213 * define the set of NominalCandidates to be
214 * {
215 * unsigned_soft(T'),
216 * unsigned_soft(U'),
217 * signed_soft(T'),
218 * signed_soft(U'),
219 * T',
220 * U',
221 * unsigned int,
222 * int
223 * }
224 * where unsigned_soft(X) is make_unsigned_soft<X>::type and
225 * signed_soft(X) is make_signed_soft<X>::type (these are all
226 * generally necessary to cover the various integral promotion cases)
227 * else
228 * define the set of NominalCandidates to be
229 * { T', U' }
230 * else
231 * let V and W be T and U stripped of reference-qualifiers
232 * define the set of NominalCandidates to be
233 * { V&, W&, V'&, W'& }
234 * where V' is V with whatever cv-qualifiers are on W, and W' is W with
235 * whatever cv-qualifiers are on V
236 * define the set of Candidates to be equal to the set of NominalCandidates with
237 * duplicates removed, and use this set of Candidates to determine C using the
238 * conversion_test_overloads struct
239 ******************************************************************************/
240
241template< class T, class U, class NominalCandidates >
242class deduce_common_type
243{
244 typedef typename mpl::copy<
245 NominalCandidates,
246 mpl::inserter<
247 mpl::vector0<>,
248 mpl::if_<
249 mpl::contains< mpl::_1, mpl::_2 >,
250 mpl::_1,
251 mpl::push_back< mpl::_1, mpl::_2 >
252 >
253 >
254 >::type candidate_types;
255 static const int best_candidate_index =
256 sizeof( conversion_test_overloads< candidate_types >::apply(
257 declval< bool >() ? declval<T>() : declval<U>()
258 ) ) - 1;
259public:
260 typedef typename select< candidate_types, best_candidate_index >::type type;
261};
262
263template<
264 class T, class U,
265 class V = typename remove_cv< typename remove_reference<T>::type >::type,
266 class W = typename remove_cv< typename remove_reference<U>::type >::type,
267 bool = is_integral_or_enum<V>::value && is_integral_or_enum<W>::value
268>
269struct nominal_candidates
270{ typedef mpl::vector2<V,W> type; };
271
272template< class T, class U, class V, class W >
273struct nominal_candidates< T, U, V, W, true >
274{
275 typedef ndnboost::mpl::vector8<
276 typename make_unsigned_soft<V>::type,
277 typename make_unsigned_soft<W>::type,
278 typename make_signed_soft<V>::type,
279 typename make_signed_soft<W>::type,
280 V, W, unsigned int, int
281 > type;
282};
283
284template< class T, class U, class V, class W >
285struct nominal_candidates< T, U, V*, W*, false >
286{
287 typedef mpl::vector4<
288 V*, W*,
289 typename propagate_cv<W,V>::type *,
290 typename propagate_cv<V,W>::type *
291 > type;
292};
293
294template<class T, class U, bool b>
295struct common_type_dispatch_on_rvalueness
296 : public deduce_common_type< T, U, typename nominal_candidates<T,U>::type >
297{ };
298
299template< class T, class U >
300struct common_type_dispatch_on_rvalueness< T, U, false >
301{
302private:
303 typedef typename remove_reference<T>::type unrefed_T_type;
304 typedef typename remove_reference<U>::type unrefed_U_type;
305public:
306 typedef typename deduce_common_type<
307 T, U,
308 mpl::vector4<
309 unrefed_T_type &,
310 unrefed_U_type &,
311 typename propagate_cv< unrefed_U_type, unrefed_T_type >::type &,
312 typename propagate_cv< unrefed_T_type, unrefed_U_type >::type &
313 >
314 >::type type;
315};
316
317template< class T, class U >
318struct common_type_impl
319 : public common_type_dispatch_on_rvalueness<T,U, sizeof( ::ndnboost::detail_type_traits_common_type::rvalue_test(
320 declval< bool >() ? declval<T>() : declval<U>() ) ) == sizeof( yes_type ) >
321{ };
322
323template< class T > struct common_type_impl< T, void > { typedef void type; };
324template< class T > struct common_type_impl< void, T > { typedef void type; };
325template<> struct common_type_impl< void, void > { typedef void type; };
326
327} // namespace detail_type_traits_common_type
328
329
330} // namespace ndnboost
331
332#endif // BOOST_TYPE_TRAITS_DETAIL_COMMON_TYPE_HPP
333