summaryrefslogtreecommitdiff
path: root/boost/hana/fwd/type.hpp
blob: d3390cf5bdc8ca18f441aae8beff217643256351 (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
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
/*!
@file
Forward declares `boost::hana::type` and related utilities.

@copyright Louis Dionne 2013-2016
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#ifndef BOOST_HANA_FWD_TYPE_HPP
#define BOOST_HANA_FWD_TYPE_HPP

#include <boost/hana/config.hpp>
#include <boost/hana/fwd/core/make.hpp>


BOOST_HANA_NAMESPACE_BEGIN
    //! Base class of `hana::type`; used for pattern-matching.
    //! @relates hana::type
    //!
    //! Example
    //! -------
    //! @include example/type/basic_type.cpp
    template <typename T>
    struct basic_type;

    //! @ingroup group-datatypes
    //! C++ type in value-level representation.
    //!
    //! A `type` is a special kind of object representing a C++ type like
    //! `int`, `void`, `std::vector<float>` or anything else you can imagine.
    //!
    //! This page explains how `type`s work at a low level. To gain
    //! intuition about type-level metaprogramming in Hana, you should
    //! read the [tutorial section](@ref tutorial-type) on type-level
    //! computations.
    //!
    //!
    //! @note
    //! For subtle reasons having to do with ADL, the actual representation of
    //! `hana::type` is implementation-defined. In particular, `hana::type`
    //! may be a dependent type, so one should not attempt to do pattern
    //! matching on it. However, one can assume that `hana::type` _inherits_
    //! from `hana::basic_type`, which can be useful when declaring overloaded
    //! functions:
    //! @code
    //!     template <typename T>
    //!     void f(hana::basic_type<T>) {
    //!         // do something with T
    //!     }
    //! @endcode
    //!
    //!
    //! @anchor type_lvalues_and_rvalues
    //! Lvalues and rvalues
    //! -------------------
    //! When storing `type`s in heterogeneous containers, some algorithms
    //! will return references to those objects. Since we are primarily
    //! interested in accessing their nested `::%type`, receiving a reference
    //! is undesirable; we would end up trying to fetch the nested `::%type`
    //! inside a reference type, which is a compilation error:
    //! @code
    //!   auto ts = make_tuple(type_c<int>, type_c<char>);
    //!   using T = decltype(ts[0_c])::type; // error: 'ts[0_c]' is a reference!
    //! @endcode
    //!
    //! For this reason, `type`s provide an overload of the unary `+`
    //! operator that can be used to turn a lvalue into a rvalue. So when
    //! using a result which might be a reference to a `type` object, one
    //! can use `+` to make sure a rvalue is obtained before fetching its
    //! nested `::%type`:
    //! @code
    //!   auto ts = make_tuple(type_c<int>, type_c<char>);
    //!   using T = decltype(+ts[0_c])::type; // ok: '+ts[0_c]' is an rvalue
    //! @endcode
    //!
    //!
    //! Modeled concepts
    //! ----------------
    //! 1. `Comparable`\n
    //! Two types are equal if and only if they represent the same C++ type.
    //! Hence, equality is equivalent to the `std::is_same` type trait.
    //! @include example/type/comparable.cpp
    //!
    //! 2. `Hashable`\n
    //! The hash of a type is just that type itself. In other words, `hash`
    //! is the identity function on `hana::type`s.
    //! @include example/type/hashable.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
    template <typename T>
    struct type {
        //! Returns rvalue of self.
        //! See @ref type_lvalues_and_rvalues "description".
        constexpr auto operator+() const;

        //! Equivalent to `hana::equal`
        template <typename X, typename Y>
        friend constexpr auto operator==(X&& x, Y&& y);

        //! Equivalent to `hana::not_equal`
        template <typename X, typename Y>
        friend constexpr auto operator!=(X&& x, Y&& y);
    };
#else
    template <typename T>
    struct type_impl;

    template <typename T>
    using type = typename type_impl<T>::_;
#endif

    //! Tag representing `hana::type`.
    //! @relates hana::type
    struct type_tag { };

    //! Creates an object representing the C++ type `T`.
    //! @relates hana::type
    template <typename T>
    constexpr type<T> type_c{};

    //! `decltype` keyword, lifted to Hana.
    //! @relates hana::type
    //!
    //! @deprecated
    //! The semantics of `decltype_` can be confusing, and `hana::typeid_`
    //! should be preferred instead. `decltype_` may be removed in the next
    //! major version of the library.
    //!
    //! `decltype_` is somewhat equivalent to `decltype` in that it returns
    //! the type of an object, except it returns it as a `hana::type` which
    //! is a first-class citizen of Hana instead of a raw C++ type.
    //! Specifically, given an object `x`, `decltype_` satisfies
    //! @code
    //!   decltype_(x) == type_c<decltype(x) with references stripped>
    //! @endcode
    //!
    //! As you can see, `decltype_` will strip any reference from the
    //! object's actual type. The reason for doing so is explained below.
    //! However, any `cv`-qualifiers will be retained. Also, when given a
    //! `hana::type`, `decltype_` is just the identity function. Hence,
    //! for any C++ type `T`,
    //! @code
    //!   decltype_(type_c<T>) == type_c<T>
    //! @endcode
    //!
    //! In conjunction with the way `metafunction` & al. are specified, this
    //! behavior makes it easier to interact with both types and values at
    //! the same time. However, it does make it impossible to create a `type`
    //! containing another `type` with `decltype_`. In other words, it is
    //! not possible to create a `type_c<decltype(type_c<T>)>` with this
    //! utility, because `decltype_(type_c<T>)` would be just `type_c<T>`
    //! instead of `type_c<decltype(type_c<T>)>`. This use case is assumed
    //! to be rare and a hand-coded function can be used if this is needed.
    //!
    //!
    //! ### Rationale for stripping the references
    //! The rules for template argument deduction are such that a perfect
    //! solution that always matches `decltype` is impossible. Hence, we
    //! have to settle on a solution that's good and and consistent enough
    //! for our needs. One case where matching `decltype`'s behavior is
    //! impossible is when the argument is a plain, unparenthesized variable
    //! or function parameter. In that case, `decltype_`'s argument will be
    //! deduced as a reference to that variable, but `decltype` would have
    //! given us the actual type of that variable, without references. Also,
    //! given the current definition of `metafunction` & al., it would be
    //! mostly useless if `decltype_` could return a reference, because it
    //! is unlikely that `F` expects a reference in its simplest use case:
    //! @code
    //!   int i = 0;
    //!   auto result = metafunction<F>(i);
    //! @endcode
    //!
    //! Hence, always discarding references seems to be the least painful
    //! solution.
    //!
    //!
    //! Example
    //! -------
    //! @include example/type/decltype.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
    constexpr auto decltype_ = see documentation;
#else
    struct decltype_t {
        template <typename T>
        constexpr auto operator()(T&&) const;
    };

    constexpr decltype_t decltype_{};
#endif

    //! Returns a `hana::type` representing the type of a given object.
    //! @relates hana::type
    //!
    //! `hana::typeid_` is somewhat similar to `typeid` in that it returns
    //! something that represents the type of an object. However, what
    //! `typeid` returns represent the _runtime_ type of the object, while
    //! `hana::typeid_` returns the _static_ type of the object. Specifically,
    //! given an object `x`, `typeid_` satisfies
    //! @code
    //!   typeid_(x) == type_c<decltype(x) with ref and cv-qualifiers stripped>
    //! @endcode
    //!
    //! As you can see, `typeid_` strips any reference and cv-qualifier from
    //! the object's actual type. The reason for doing so is that it faithfully
    //! models how the language's `typeid` behaves with respect to reference
    //! and cv-qualifiers, and it also turns out to be the desirable behavior
    //! most of the time. Also, when given a `hana::type`, `typeid_` is just
    //! the identity function. Hence, for any C++ type `T`,
    //! @code
    //!   typeid_(type_c<T>) == type_c<T>
    //! @endcode
    //!
    //! In conjunction with the way `metafunction` & al. are specified, this
    //! behavior makes it easier to interact with both types and values at
    //! the same time. However, it does make it impossible to create a `type`
    //! containing another `type` using `typeid_`. This use case is assumed
    //! to be rare and a hand-coded function can be used if this is needed.
    //!
    //!
    //! Example
    //! -------
    //! @include example/type/typeid.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
    constexpr auto typeid_ = see documentation;
#else
    struct typeid_t {
        template <typename T>
        constexpr auto operator()(T&&) const;
    };

    constexpr typeid_t typeid_{};
#endif

#ifdef BOOST_HANA_DOXYGEN_INVOKED
    //! Equivalent to `decltype_`, provided for convenience.
    //! @relates hana::type
    //!
    //!
    //! Example
    //! -------
    //! @include example/type/make.cpp
    template <>
    constexpr auto make<type_tag> = hana::decltype_;
#endif

    //! Equivalent to `make<type_tag>`, provided for convenience.
    //! @relates hana::type
    //!
    //!
    //! Example
    //! -------
    //! @include example/type/make.cpp
    constexpr auto make_type = hana::make<type_tag>;

    //! `sizeof` keyword, lifted to Hana.
    //! @relates hana::type
    //!
    //! `sizeof_` is somewhat equivalent to `sizeof` in that it returns the
    //! size of an expression or type, but it takes an arbitrary expression
    //! or a `hana::type` and returns its size as an `integral_constant`.
    //! Specifically, given an expression `expr`, `sizeof_` satisfies
    //! @code
    //!   sizeof_(expr) == size_t<sizeof(decltype(expr) with references stripped)>
    //! @endcode
    //!
    //! However, given a `type`, `sizeof_` will simply fetch the size
    //! of the C++ type represented by that object. In other words,
    //! @code
    //!   sizeof_(type_c<T>) == size_t<sizeof(T)>
    //! @endcode
    //!
    //! The behavior of `sizeof_` is consistent with that of `decltype_`.
    //! In particular, see `decltype_`'s documentation to understand why
    //! references are always stripped by `sizeof_`.
    //!
    //!
    //! Example
    //! -------
    //! @include example/type/sizeof.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
    constexpr auto sizeof_ = [](auto&& x) {
        using T = typename decltype(hana::decltype_(x))::type;
        return hana::size_c<sizeof(T)>;
    };
#else
    struct sizeof_t {
        template <typename T>
        constexpr auto operator()(T&&) const;
    };

    constexpr sizeof_t sizeof_{};
#endif

    //! `alignof` keyword, lifted to Hana.
    //! @relates hana::type
    //!
    //! `alignof_` is somewhat equivalent to `alignof` in that it returns the
    //! alignment required by any instance of a type, but it takes a `type`
    //! and returns its alignment as an `integral_constant`. Like `sizeof`
    //! which works for expressions and type-ids, `alignof_` can also be
    //! called on an arbitrary expression. Specifically, given an expression
    //! `expr` and a C++ type `T`, `alignof_` satisfies
    //! @code
    //!   alignof_(expr) == size_t<alignof(decltype(expr) with references stripped)>
    //!   alignof_(type_c<T>) == size_t<alignof(T)>
    //! @endcode
    //!
    //! The behavior of `alignof_` is consistent with that of `decltype_`.
    //! In particular, see `decltype_`'s documentation to understand why
    //! references are always stripped by `alignof_`.
    //!
    //!
    //! Example
    //! -------
    //! @include example/type/alignof.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
    constexpr auto alignof_ = [](auto&& x) {
        using T = typename decltype(hana::decltype_(x))::type;
        return hana::size_c<alignof(T)>;
    };
#else
    struct alignof_t {
        template <typename T>
        constexpr auto operator()(T&&) const;
    };

    constexpr alignof_t alignof_{};
#endif

    //! Checks whether a SFINAE-friendly expression is valid.
    //! @relates hana::type
    //!
    //! Given a SFINAE-friendly function, `is_valid` returns whether the
    //! function call is valid with the given arguments. Specifically, given
    //! a function `f` and arguments `args...`,
    //! @code
    //!   is_valid(f, args...) == whether f(args...) is valid
    //! @endcode
    //!
    //! The result is returned as a compile-time `Logical`. Furthermore,
    //! `is_valid` can be used in curried form as follows:
    //! @code
    //!   is_valid(f)(args...)
    //! @endcode
    //!
    //! This syntax makes it easy to create functions that check the validity
    //! of a generic expression on any given argument(s).
    //!
    //! @warning
    //! To check whether calling a nullary function `f` is valid, one should
    //! use the `is_valid(f)()` syntax. Indeed, `is_valid(f /* no args */)`
    //! will be interpreted as the currying of `is_valid` to `f` rather than
    //! the application of `is_valid` to `f` and no arguments.
    //!
    //!
    //! Example
    //! -------
    //! @include example/type/is_valid.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
    constexpr auto is_valid = [](auto&& f) {
        return [](auto&& ...args) {
            return whether f(args...) is a valid expression;
        };
    };
#else
    struct is_valid_t {
        template <typename F>
        constexpr auto operator()(F&&) const;

        template <typename F, typename ...Args>
        constexpr auto operator()(F&&, Args&&...) const;
    };

    constexpr is_valid_t is_valid{};
#endif

    //! Lift a template to a Metafunction.
    //! @ingroup group-Metafunction
    //!
    //! Given a template class or template alias `f`, `template_<f>` is a
    //! `Metafunction` satisfying
    //! @code
    //!     template_<f>(type_c<x>...) == type_c<f<x...>>
    //!     decltype(template_<f>)::apply<x...>::type == f<x...>
    //! @endcode
    //!
    //! @note
    //! `template_` can't be SFINAE-friendly right now because of
    //! [Core issue 1430][1].
    //!
    //!
    //! Example
    //! -------
    //! @include example/type/template.cpp
    //!
    //! [1]: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1430
#ifdef BOOST_HANA_DOXYGEN_INVOKED
    template <template <typename ...> class F>
    constexpr auto template_ = [](basic_type<T>...) {
        return hana::type_c<F<T...>>;
    };
#else
    template <template <typename ...> class F>
    struct template_t;

    template <template <typename ...> class F>
    constexpr template_t<F> template_{};
#endif

    //! Lift a MPL-style metafunction to a Metafunction.
    //! @ingroup group-Metafunction
    //!
    //! Given a MPL-style metafunction, `metafunction<f>` is a `Metafunction`
    //! satisfying
    //! @code
    //!     metafunction<f>(type_c<x>...) == type_c<f<x...>::type>
    //!     decltype(metafunction<f>)::apply<x...>::type == f<x...>::type
    //! @endcode
    //!
    //!
    //! Example
    //! -------
    //! @include example/type/metafunction.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
    template <template <typename ...> class F>
    constexpr auto metafunction = [](basic_type<T>...) {
        return hana::type_c<typename F<T...>::type>;
    };
#else
    template <template <typename ...> class f>
    struct metafunction_t;

    template <template <typename ...> class f>
    constexpr metafunction_t<f> metafunction{};
#endif

    //! Lift a MPL-style metafunction class to a Metafunction.
    //! @ingroup group-Metafunction
    //!
    //! Given a MPL-style metafunction class, `metafunction_class<f>` is a
    //! `Metafunction` satisfying
    //! @code
    //!     metafunction_class<f>(type_c<x>...) == type_c<f::apply<x...>::type>
    //!     decltype(metafunction_class<f>)::apply<x...>::type == f::apply<x...>::type
    //! @endcode
    //!
    //!
    //! Example
    //! -------
    //! @include example/type/metafunction_class.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
    template <typename F>
    constexpr auto metafunction_class = [](basic_type<T>...) {
        return hana::type_c<typename F::template apply<T...>::type>;
    };
#else
    template <typename F>
    struct metafunction_class_t
        : metafunction_t<F::template apply>
    { };

    template <typename F>
    constexpr metafunction_class_t<F> metafunction_class{};
#endif

    //! Turn a `Metafunction` into a function taking `type`s and returning a
    //! default-constructed object.
    //! @ingroup group-Metafunction
    //!
    //! Given a `Metafunction` `f`, `integral` returns a new `Metafunction`
    //! that default-constructs an object of the type returned by `f`. More
    //! specifically, the following holds:
    //! @code
    //!     integral(f)(t...) == decltype(f(t...))::type{}
    //! @endcode
    //!
    //! The principal use case for `integral` is to transform `Metafunction`s
    //! returning a type that inherits from a meaningful base like
    //! `std::integral_constant` into functions returning e.g. a
    //! `hana::integral_constant`.
    //!
    //! @note
    //! - This is not a `Metafunction` because it does not return a `type`.
    //!   As such, it would not make sense to make `decltype(integral(f))`
    //!   a MPL metafunction class like the usual `Metafunction`s are.
    //!
    //! - When using `integral` with metafunctions returning
    //!   `std::integral_constant`s, don't forget to include the
    //!   boost/hana/ext/std/integral_constant.hpp header to ensure
    //!   Hana can interoperate with the result.
    //!
    //!
    //! Example
    //! -------
    //! @include example/type/integral.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
    constexpr auto integral = [](auto f) {
        return [](basic_type<T>...) {
            return decltype(f)::apply<T...>::type{};
        };
    };
#else
    template <typename F>
    struct integral_t;

    struct make_integral_t {
        template <typename F>
        constexpr integral_t<F> operator()(F const&) const
        { return {}; }
    };

    constexpr make_integral_t integral{};
#endif

    //! Alias to `integral(metafunction<F>)`, provided for convenience.
    //! @ingroup group-Metafunction
    //!
    //!
    //! Example
    //! -------
    //! @include example/type/trait.cpp
    template <template <typename ...> class F>
    constexpr auto trait = hana::integral(hana::metafunction<F>);
BOOST_HANA_NAMESPACE_END

#endif // !BOOST_HANA_FWD_TYPE_HPP