Jeff Thompson | a28eed8 | 2013-08-22 16:21:10 -0700 | [diff] [blame] | 1 | /******************************************************************************* |
| 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 | |
| 49 | namespace ndnboost |
| 50 | { |
| 51 | |
| 52 | namespace 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 | |
| 61 | template< class From, class To > |
| 62 | struct propagate_cv |
| 63 | { typedef To type; }; |
| 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; }; |
| 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 | |
| 81 | template< class T > |
| 82 | struct is_integral_or_enum |
| 83 | : public mpl::or_< is_integral<T>, is_enum<T> > |
| 84 | { }; |
| 85 | template<> |
| 86 | struct 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 | |
| 98 | template< class T > |
| 99 | struct make_unsigned_soft |
| 100 | : public make_unsigned<T> |
| 101 | { }; |
| 102 | template<> |
| 103 | struct make_unsigned_soft< bool > |
| 104 | { typedef bool type; }; |
| 105 | |
| 106 | template< class T > |
| 107 | struct make_signed_soft |
| 108 | : public make_signed<T> |
| 109 | { }; |
| 110 | template<> |
| 111 | struct 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 | |
| 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 ); |
| 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 | |
| 137 | template< class T > no_type rvalue_test(T&); |
| 138 | yes_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 | |
| 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 |
| 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 | |
| 165 | template< class Last, std::size_t Index > |
| 166 | struct conversion_test_overloads_iterate< Last, Last, Index > |
| 167 | { static sizeof_t< Index + 1 > apply(...); }; |
| 168 | |
| 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, |
| 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 | |
| 185 | template< |
| 186 | class Sequence, int Index, |
| 187 | int N = mpl::size< Sequence >::value |
| 188 | > |
| 189 | struct select |
| 190 | : public mpl::at_c< Sequence, Index > |
| 191 | { }; |
| 192 | template< class Sequence, int N > |
| 193 | struct 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 | |
| 241 | template< class T, class U, class NominalCandidates > |
| 242 | class 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; |
| 259 | public: |
| 260 | typedef typename select< candidate_types, best_candidate_index >::type type; |
| 261 | }; |
| 262 | |
| 263 | template< |
| 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 | > |
| 269 | struct nominal_candidates |
| 270 | { typedef mpl::vector2<V,W> type; }; |
| 271 | |
| 272 | template< class T, class U, class V, class W > |
| 273 | struct 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 | |
| 284 | template< class T, class U, class V, class W > |
| 285 | struct 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 | |
| 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 > |
| 297 | { }; |
| 298 | |
| 299 | template< class T, class U > |
| 300 | struct common_type_dispatch_on_rvalueness< T, U, false > |
| 301 | { |
| 302 | private: |
| 303 | typedef typename remove_reference<T>::type unrefed_T_type; |
| 304 | typedef typename remove_reference<U>::type unrefed_U_type; |
| 305 | public: |
| 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 | |
| 317 | template< class T, class U > |
| 318 | struct 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 | |
| 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; }; |
| 326 | |
| 327 | } // namespace detail_type_traits_common_type |
| 328 | |
| 329 | |
| 330 | } // namespace ndnboost |
| 331 | |
| 332 | #endif // BOOST_TYPE_TRAITS_DETAIL_COMMON_TYPE_HPP |
| 333 | |