1 /*******************************************************************************
2 * boost/type_traits/detail/common_type_imp.hpp
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)
8 * struct boost::common_type<T,U>
10 * common_type<T,U>::type is the type of the expression
12 * where b() returns a bool, x() has return type T, and y() has return type U.
14 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm#common_type
16 * Note that this evaluates to void if one or both of T and U is void.
17 ******************************************************************************/
19 #ifndef BOOST_TYPE_TRAITS_DETAIL_COMMON_TYPE_IMP_HPP
20 #define BOOST_TYPE_TRAITS_DETAIL_COMMON_TYPE_IMP_HPP
24 #include <boost/mpl/assert.hpp>
25 #include <boost/mpl/at.hpp>
26 #include <boost/mpl/begin_end.hpp>
27 #include <boost/mpl/contains.hpp>
28 #include <boost/mpl/copy.hpp>
29 #include <boost/mpl/deref.hpp>
30 #include <boost/mpl/eval_if.hpp>
31 #include <boost/mpl/if.hpp>
32 #include <boost/mpl/inserter.hpp>
33 #include <boost/mpl/next.hpp>
34 #include <boost/mpl/or.hpp>
35 #include <boost/mpl/placeholders.hpp>
36 #include <boost/mpl/push_back.hpp>
37 #include <boost/mpl/size.hpp>
38 #include <boost/mpl/vector/vector0.hpp>
39 #include <boost/mpl/vector/vector10.hpp>
40 #include <boost/type_traits/integral_constant.hpp>
41 #include <boost/type_traits/is_enum.hpp>
42 #include <boost/type_traits/is_integral.hpp>
43 #include <boost/type_traits/make_signed.hpp>
44 #include <boost/type_traits/make_unsigned.hpp>
45 #include <boost/type_traits/remove_cv.hpp>
46 #include <boost/type_traits/remove_reference.hpp>
47 #include <boost/utility/declval.hpp>
52 namespace detail_type_traits_common_type
55 /*******************************************************************************
56 * struct propagate_cv< From, To >
58 * This metafunction propagates cv-qualifiers on type From to type To.
59 ******************************************************************************/
61 template< class From, class To >
64 template< class From, class To >
65 struct propagate_cv< const From, To >
66 { typedef To const type; };
67 template< class From, class To >
68 struct propagate_cv< volatile From, To >
69 { typedef To volatile type; };
70 template< class From, class To >
71 struct propagate_cv< const volatile From, To >
72 { typedef To const volatile type; };
74 /*******************************************************************************
75 * struct is_integral_or_enum<T>
77 * This metafunction determines if T is an integral type which can be made
79 ******************************************************************************/
82 struct is_integral_or_enum
83 : public mpl::or_< is_integral<T>, is_enum<T> >
86 struct is_integral_or_enum< bool >
90 /*******************************************************************************
91 * struct make_unsigned_soft<T>
92 * struct make_signed_soft<T>
94 * These metafunction are identical to make_unsigned and make_signed,
95 * respectively, except for special-casing bool.
96 ******************************************************************************/
99 struct make_unsigned_soft
100 : public make_unsigned<T>
103 struct make_unsigned_soft< bool >
104 { typedef bool type; };
107 struct make_signed_soft
108 : public make_signed<T>
111 struct make_signed_soft< bool >
112 { typedef bool type; };
114 /*******************************************************************************
116 * typedef ... yes_type
117 * typedef ... no_type
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
122 ******************************************************************************/
124 template< std::size_t N > struct sizeof_t { char _dummy[N]; };
125 typedef sizeof_t<1> yes_type;
126 typedef sizeof_t<2> no_type;
127 BOOST_MPL_ASSERT_RELATION( sizeof( yes_type ), ==, 1 );
128 BOOST_MPL_ASSERT_RELATION( sizeof( no_type ), ==, 2 );
130 /*******************************************************************************
131 * rvalue_test(T&) -> no_type
132 * rvalue_test(...) -> yes_type
134 * These overloads are used to determine the rvalue-ness of an expression.
135 ******************************************************************************/
137 template< class T > no_type rvalue_test(T&);
138 yes_type rvalue_test(...);
140 /*******************************************************************************
141 * struct conversion_test_overloads< Sequence >
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
150 ******************************************************************************/
152 template< class First, class Last, std::size_t Index >
153 struct conversion_test_overloads_iterate
154 : public conversion_test_overloads_iterate<
155 typename mpl::next< First >::type, Last, Index + 1
158 using conversion_test_overloads_iterate<
159 typename mpl::next< First >::type, Last, Index + 1
161 static sizeof_t< Index + 1 >
162 apply(typename mpl::deref< First >::type);
165 template< class Last, std::size_t Index >
166 struct conversion_test_overloads_iterate< Last, Last, Index >
167 { static sizeof_t< Index + 1 > apply(...); };
169 template< class Sequence >
170 struct conversion_test_overloads
171 : public conversion_test_overloads_iterate<
172 typename mpl::begin< Sequence >::type,
173 typename mpl::end< Sequence >::type,
178 /*******************************************************************************
179 * struct select< Sequence, Index >
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 ******************************************************************************/
186 class Sequence, int Index,
187 int N = mpl::size< Sequence >::value
190 : public mpl::at_c< Sequence, Index >
192 template< class Sequence, int N >
193 struct select< Sequence, N, N >
194 { typedef void type; };
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>
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
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)
228 * define the set of NominalCandidates to be
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 ******************************************************************************/
241 template< class T, class U, class NominalCandidates >
242 class deduce_common_type
244 typedef typename mpl::copy<
249 mpl::contains< mpl::_1, mpl::_2 >,
251 mpl::push_back< mpl::_1, mpl::_2 >
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>()
260 typedef typename select< candidate_types, best_candidate_index >::type type;
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
269 struct nominal_candidates
270 { typedef mpl::vector2<V,W> type; };
272 template< class T, class U, class V, class W >
273 struct nominal_candidates< T, U, V, W, true >
275 typedef boost::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
284 template< class T, class U, class V, class W >
285 struct nominal_candidates< T, U, V*, W*, false >
287 typedef mpl::vector4<
289 typename propagate_cv<W,V>::type *,
290 typename propagate_cv<V,W>::type *
294 template<class T, class U, bool b>
295 struct common_type_dispatch_on_rvalueness
296 : public deduce_common_type< T, U, typename nominal_candidates<T,U>::type >
299 template< class T, class U >
300 struct common_type_dispatch_on_rvalueness< T, U, false >
303 typedef typename remove_reference<T>::type unrefed_T_type;
304 typedef typename remove_reference<U>::type unrefed_U_type;
306 typedef typename deduce_common_type<
311 typename propagate_cv< unrefed_U_type, unrefed_T_type >::type &,
312 typename propagate_cv< unrefed_T_type, unrefed_U_type >::type &
317 template< class T, class U >
318 struct common_type_impl
319 : public common_type_dispatch_on_rvalueness<T,U, sizeof( ::boost::detail_type_traits_common_type::rvalue_test(
320 declval< bool >() ? declval<T>() : declval<U>() ) ) == sizeof( yes_type ) >
323 template< class T > struct common_type_impl< T, void > { typedef void type; };
324 template< class T > struct common_type_impl< void, T > { typedef void type; };
325 template<> struct common_type_impl< void, void > { typedef void type; };
327 } // namespace detail_type_traits_common_type
332 #endif // BOOST_TYPE_TRAITS_DETAIL_COMMON_TYPE_HPP