summaryrefslogtreecommitdiffstats
blob: 9e06282bcfd478d1c6ab174c0b961cb84a451592 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
/*******************************************************************************
 * boost/type_traits/detail/common_type_imp.hpp
 *
 * Copyright 2010, Jeffrey Hellrung.
 * Distributed under the Boost Software License, Version 1.0.  (See accompanying
 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 *
 * struct boost::common_type<T,U>
 *
 * common_type<T,U>::type is the type of the expression
 *     b() ? x() : y()
 * where b() returns a bool, x() has return type T, and y() has return type U.
 * See
 *     http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm#common_type
 *
 * Note that this evaluates to void if one or both of T and U is void.
 ******************************************************************************/

#ifndef BOOST_TYPE_TRAITS_DETAIL_COMMON_TYPE_IMP_HPP
#define BOOST_TYPE_TRAITS_DETAIL_COMMON_TYPE_IMP_HPP

#include <cstddef>

#include <boost/mpl/assert.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/contains.hpp>
#include <boost/mpl/copy.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/inserter.hpp>
#include <boost/mpl/next.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/vector/vector0.hpp>
#include <boost/mpl/vector/vector10.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/type_traits/is_enum.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/make_signed.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/utility/declval.hpp>

namespace boost
{

namespace detail_type_traits_common_type
{

/*******************************************************************************
 * struct propagate_cv< From, To >
 *
 * This metafunction propagates cv-qualifiers on type From to type To.
 ******************************************************************************/

template< class From, class To >
struct propagate_cv
{ typedef To type; };
template< class From, class To >
struct propagate_cv< const From, To >
{ typedef To const type; };
template< class From, class To >
struct propagate_cv< volatile From, To >
{ typedef To volatile type; };
template< class From, class To >
struct propagate_cv< const volatile From, To >
{ typedef To const volatile type; };

/*******************************************************************************
 * struct is_signable_integral<T>
 *
 * This metafunction determines if T is an integral type which can be made
 * signed or unsigned.
 ******************************************************************************/

template< class T >
struct is_signable_integral
    : mpl::or_< is_integral<T>, is_enum<T> >
{ };
template<>
struct is_signable_integral< bool >
    : false_type
{ };

/*******************************************************************************
 * struct sizeof_t<N>
 * typedef ... yes_type
 * typedef ... no_type
 *
 * These types are integral players in the use of the "sizeof trick", i.e., we
 * can distinguish overload selection by inspecting the size of the return type
 * of the overload.
 ******************************************************************************/

template< std::size_t N > struct sizeof_t { char _dummy[N]; };
typedef sizeof_t<1> yes_type;
typedef sizeof_t<2> no_type;
BOOST_MPL_ASSERT_RELATION( sizeof( yes_type ), ==, 1 );
BOOST_MPL_ASSERT_RELATION( sizeof( no_type ), ==, 2 );

/*******************************************************************************
 * rvalue_test(T&) -> no_type
 * rvalue_test(...) -> yes_type
 *
 * These overloads are used to determine the rvalue-ness of an expression.
 ******************************************************************************/

template< class T > no_type rvalue_test(T&);
yes_type rvalue_test(...);

/*******************************************************************************
 * struct conversion_test_overloads< Sequence >
 *
 * This struct has multiple overloads of the static member function apply, each
 * one taking a single parameter of a type within the Boost.MPL sequence
 * Sequence.  Each such apply overload has a return type with sizeof equal to
 * one plus the index of the parameter type within Sequence.  Thus, we can
 * deduce the type T of an expression as long as we can generate a finite set of
 * candidate types containing T via these apply overloads and the "sizeof
 * trick".
 ******************************************************************************/

template< class First, class Last, std::size_t Index >
struct conversion_test_overloads_iterate
    : conversion_test_overloads_iterate<
          typename mpl::next< First >::type, Last, Index + 1
      >
{
    using conversion_test_overloads_iterate<
        typename mpl::next< First >::type, Last, Index + 1
    >::apply;
    static sizeof_t< Index + 1 >
    apply(typename mpl::deref< First >::type);
};

template< class Last, std::size_t Index >
struct conversion_test_overloads_iterate< Last, Last, Index >
{ static sizeof_t< Index + 1 > apply(...); };

template< class Sequence >
struct conversion_test_overloads
    : conversion_test_overloads_iterate<
          typename mpl::begin< Sequence >::type,
          typename mpl::end< Sequence >::type,
          0
      >
{ };

/*******************************************************************************
 * struct select< Sequence, Index >
 *
 * select is synonymous with mpl::at_c unless Index equals the size of the
 * Boost.MPL Sequence, in which case this evaluates to void.
 ******************************************************************************/

template<
    class Sequence, int Index,
    int N = mpl::size< Sequence >::value
>
struct select
    : mpl::at_c< Sequence, Index >
{ };
template< class Sequence, int N >
struct select< Sequence, N, N >
{ typedef void type; };

/*******************************************************************************
 * class deduce_common_type< T, U, NominalCandidates >
 * struct nominal_candidates<T,U>
 * struct common_type_dispatch_on_rvalueness<T,U>
 * struct common_type_impl<T,U>
 *
 * These classes and structs implement the logic behind common_type, which goes
 * roughly as follows.  Let C be the type of the conditional expression
 *     declval< bool >() ? declval<T>() : declval<U>()
 * if C is an rvalue, then:
 *     let T' and U' be T and U stripped of reference- and cv-qualifiers
 *     if T' and U' are pointer types, say, T' = V* and U' = W*, then:
 *         define the set of NominalCandidates to be
 *             { V*, W*, V'*, W'* }
 *           where V' is V with whatever cv-qualifiers are on W, and W' is W
 *           with whatever cv-qualifiers are on V
 *     else T' and U' are both "signable integral types" (integral and enum
 *       types excepting bool), then:
 *         define the set of NominalCandidates to be
 *             { unsigned(T'), unsigned(U'), signed(T'), signed(U') }
 *           where unsigned(X) is make_unsigned<X>::type and signed(X) is
 *           make_signed<X>::type
 *     else
 *         define the set of NominalCandidates to be
 *             { T', U' }
 * else
 *     let V and W be T and U stripped of reference-qualifiers
 *     define the set of NominalCandidates to be
 *         { V&, W&, V'&, W'& }
 *     where V' is V with whatever cv-qualifiers are on W, and W' is W with
 *       whatever cv-qualifiers are on V
 * define the set of Candidates to be equal to the set of NominalCandidates with
 * duplicates removed, and use this set of Candidates to determine C using the
 * conversion_test_overloads struct
 ******************************************************************************/

template< class T, class U, class NominalCandidates >
class deduce_common_type
{
    typedef typename mpl::copy<
        NominalCandidates,
        mpl::inserter<
            mpl::vector0<>,
            mpl::if_<
                mpl::contains< mpl::_1, mpl::_2 >,
                mpl::_1,
                mpl::push_back< mpl::_1, mpl::_2 >
            >
        >
    >::type candidate_types;
    static const int best_candidate_index =
        sizeof( conversion_test_overloads< candidate_types >::apply(
            declval< bool >() ? declval<T>() : declval<U>()
        ) ) - 1;
public:
    typedef typename select< candidate_types, best_candidate_index >::type type;
};

template<
    class T, class U,
    class V = typename remove_cv< typename remove_reference<T>::type >::type,
    class W = typename remove_cv< typename remove_reference<U>::type >::type,
    bool = is_signable_integral<V>::value && is_signable_integral<W>::value
>
struct nominal_candidates;

template< class T, class U, class V, class W >
struct nominal_candidates< T, U, V, W, false >
{ typedef mpl::vector2<V,W> type; };

template< class T, class U, class V, class W >
struct nominal_candidates< T, U, V, W, true >
{
    typedef mpl::vector4<
        typename make_unsigned<V>::type,
        typename make_unsigned<W>::type,
        typename make_signed<V>::type,
        typename make_signed<W>::type
    > type;
};

template< class T, class U, class V, class W >
struct nominal_candidates< T, U, V*, W*, false >
{
    typedef mpl::vector4<
        V*, W*,
        typename propagate_cv<W,V>::type *,
        typename propagate_cv<V,W>::type *
    > type;
};

template<class T, class U, bool b>
struct common_type_dispatch_on_rvalueness
    : deduce_common_type< T, U, typename nominal_candidates<T,U>::type >
{ };

template< class T, class U >
struct common_type_dispatch_on_rvalueness< T, U, false >
{
private:
    typedef typename remove_reference<T>::type unrefed_T_type;
    typedef typename remove_reference<U>::type unrefed_U_type;
public:
    typedef typename deduce_common_type<
        T, U,
        mpl::vector4<
            unrefed_T_type &,
            unrefed_U_type &,
            typename propagate_cv< unrefed_U_type, unrefed_T_type >::type &,
            typename propagate_cv< unrefed_T_type, unrefed_U_type >::type &
        >
    >::type type;
};

template< class T, class U >
struct common_type_impl
    : common_type_dispatch_on_rvalueness<T,U, sizeof( ::boost::detail_type_traits_common_type::rvalue_test(
        declval< bool >() ? declval<T>() : declval<U>() ) ) == sizeof( yes_type ) >
{ };

template< class T > struct common_type_impl< T, void > { typedef void type; };
template< class T > struct common_type_impl< void, T > { typedef void type; };
template<> struct common_type_impl< void, void > { typedef void type; };

} // namespace detail_type_traits_common_type


} // namespace boost

#endif // BOOST_TYPE_TRAITS_DETAIL_COMMON_TYPE_HPP