| 1 | /*! |
| 2 | @file |
| 3 | Forward declares `boost::hana::to` and related utilities. |
| 4 | |
| 5 | Copyright Louis Dionne 2013-2022 |
| 6 | Distributed under the Boost Software License, Version 1.0. |
| 7 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) |
| 8 | */ |
| 9 | |
| 10 | #ifndef BOOST_HANA_FWD_CORE_TO_HPP |
| 11 | #define BOOST_HANA_FWD_CORE_TO_HPP |
| 12 | |
| 13 | #include <boost/hana/config.hpp> |
| 14 | |
| 15 | |
| 16 | namespace boost { namespace hana { |
| 17 | //! @ingroup group-core |
| 18 | //! Converts an object from one data type to another. |
| 19 | //! |
| 20 | //! `to` is a natural extension of the `static_cast` language construct to |
| 21 | //! data types. Given a destination data type `To` and an object `x`, `to` |
| 22 | //! creates a new object of data type `To` from `x`. Note, however, that |
| 23 | //! `to` is not required to actually create a new object, and may return a |
| 24 | //! reference to the original object (for example when trying to convert |
| 25 | //! an object to its own data type). |
| 26 | //! |
| 27 | //! As a natural extension to `static_cast`, `to` provides a default |
| 28 | //! behavior. For the purpose of what follows, let `To` be the destination |
| 29 | //! data type and `From` be the data type of `x`, i.e. the source data type. |
| 30 | //! Then, `to` has the following default behavior: |
| 31 | //! 1. If the `To` and `From` data types are the same, then the object |
| 32 | //! is forwarded as-is. |
| 33 | //! 2. Otherwise, if `From` is convertible to `To` using `static_cast`, |
| 34 | //! `x` is converted to `From` using `static_cast`. |
| 35 | //! 3. Otherwise, calling `to<From>(x)` triggers a static assertion. |
| 36 | //! |
| 37 | //! However, `to` is a tag-dispatched function, which means that `to_impl` |
| 38 | //! may be specialized in the `boost::hana` namespace to customize its |
| 39 | //! behavior for arbitrary data types. Also note that `to` is tag-dispatched |
| 40 | //! using both the `To` and the `From` data types, which means that `to_impl` |
| 41 | //! is called as `to_impl<To, From>::%apply(x)`. Also note that some |
| 42 | //! concepts provide conversions to or from their models. For example, |
| 43 | //! any `Foldable` may be converted into a `Sequence`. This is achieved |
| 44 | //! by specializing `to_impl<To, From>` whenever `To` is a `Sequence` and |
| 45 | //! `From` is a `Foldable`. When such conversions are provided, they are |
| 46 | //! documented in the source concept, in this case `Foldable`. |
| 47 | //! |
| 48 | //! |
| 49 | //! Hana-convertibility |
| 50 | //! ------------------- |
| 51 | //! When an object `x` of data type `From` can be converted to a data type |
| 52 | //! `To` using `to`, we say that `x` is Hana-convertible to the data type |
| 53 | //! `To`. We also say that there is a Hana-conversion from `From` to `To`. |
| 54 | //! This bit of terminology is useful to avoid mistaking the various kinds |
| 55 | //! of conversions C++ offers. |
| 56 | //! |
| 57 | //! |
| 58 | //! Embeddings |
| 59 | //! ---------- |
| 60 | //! As you might have seen by now, Hana uses algebraic and category- |
| 61 | //! theoretical structures all around the place to help specify concepts |
| 62 | //! in a rigorous way. These structures always have operations associated |
| 63 | //! to them, which is why they are useful. The notion of embedding captures |
| 64 | //! the idea of injecting a smaller structure into a larger one while |
| 65 | //! preserving the operations of the structure. In other words, an |
| 66 | //! embedding is an injective mapping that is also structure-preserving. |
| 67 | //! Exactly what it means for a structure's operations to be preserved is |
| 68 | //! left to explain by the documentation of each structure. For example, |
| 69 | //! when we talk of a Monoid-embedding from a Monoid `A` to a Monoid `B`, |
| 70 | //! we simply mean an injective transformation that preserves the identity |
| 71 | //! and the associative operation, as documented in `Monoid`. |
| 72 | //! |
| 73 | //! But what does this have to do with the `to` function? Quite simply, |
| 74 | //! the `to` function is a mapping between two data types, which will |
| 75 | //! sometimes be some kind of structure, and it is sometimes useful to |
| 76 | //! know whether such a mapping is well-behaved, i.e. lossless and |
| 77 | //! structure preserving. The criterion for this conversion to be well- |
| 78 | //! behaved is exactly that of being an embedding. To specify that a |
| 79 | //! conversion is an embedding, simply use the `embedding` type as a |
| 80 | //! base class of the corresponding `to_impl` specialization. Obviously, |
| 81 | //! you should make sure the conversion is really an embedding, unless |
| 82 | //! you want to shoot yourself in the foot. |
| 83 | //! |
| 84 | //! |
| 85 | //! @tparam To |
| 86 | //! The data type to which `x` should be converted. |
| 87 | //! |
| 88 | //! @param x |
| 89 | //! The object to convert to the given data type. |
| 90 | //! |
| 91 | //! |
| 92 | //! Example |
| 93 | //! ------- |
| 94 | //! @include example/core/convert/to.cpp |
| 95 | #ifdef BOOST_HANA_DOXYGEN_INVOKED |
| 96 | template <typename To> |
| 97 | constexpr auto to = [](auto&& x) -> decltype(auto) { |
| 98 | return tag-dispatched; |
| 99 | }; |
| 100 | #else |
| 101 | template <typename To, typename From, typename = void> |
| 102 | struct to_impl; |
| 103 | |
| 104 | template <typename To> |
| 105 | struct to_t { |
| 106 | template <typename X> |
| 107 | constexpr decltype(auto) operator()(X&& x) const; |
| 108 | }; |
| 109 | |
| 110 | template <typename To> |
| 111 | BOOST_HANA_INLINE_VARIABLE constexpr to_t<To> to{}; |
| 112 | #endif |
| 113 | |
| 114 | //! @ingroup group-core |
| 115 | //! Returns whether there is a Hana-conversion from a data type to another. |
| 116 | //! |
| 117 | //! Specifically, `is_convertible<From, To>` is whether calling `to<To>` |
| 118 | //! with an object of data type `From` would _not_ trigger a static |
| 119 | //! assertion. |
| 120 | //! |
| 121 | //! |
| 122 | //! Example |
| 123 | //! ------- |
| 124 | //! @include example/core/convert/is_convertible.cpp |
| 125 | #ifdef BOOST_HANA_DOXYGEN_INVOKED |
| 126 | template <typename From, typename To> |
| 127 | struct is_convertible { see documentation }; |
| 128 | #else |
| 129 | template <typename From, typename To, typename = void> |
| 130 | struct is_convertible; |
| 131 | #endif |
| 132 | |
| 133 | //! @ingroup group-core |
| 134 | //! Marks a conversion between data types as being an embedding. |
| 135 | //! |
| 136 | //! To mark a conversion between two data types `To` and `From` as |
| 137 | //! an embedding, simply use `embedding<true>` (or simply `embedding<>`) |
| 138 | //! as a base class of the corresponding `to_impl` specialization. |
| 139 | //! If a `to_impl` specialization does not inherit `embedding<true>` |
| 140 | //! or `embedding<>`, then it is not considered an embedding by the |
| 141 | //! `is_embedded` metafunction. |
| 142 | //! |
| 143 | //! > #### Tip |
| 144 | //! > The boolean template parameter is useful for marking a conversion |
| 145 | //! > as an embedding only when some condition is satisfied. |
| 146 | //! |
| 147 | //! |
| 148 | //! Example |
| 149 | //! ------- |
| 150 | //! @include example/core/convert/embedding.cpp |
| 151 | template <bool = true> |
| 152 | struct embedding { }; |
| 153 | |
| 154 | //! @ingroup group-core |
| 155 | //! Returns whether a data type can be embedded into another data type. |
| 156 | //! |
| 157 | //! Given two data types `To` and `From`, `is_embedded<From, To>` returns |
| 158 | //! whether `From` is convertible to `To`, and whether that conversion is |
| 159 | //! also an embedding, as signaled by the `embedding` type. |
| 160 | //! |
| 161 | //! |
| 162 | //! Example |
| 163 | //! ------- |
| 164 | //! @include example/core/convert/is_embedded.cpp |
| 165 | #ifdef BOOST_HANA_DOXYGEN_INVOKED |
| 166 | template <typename From, typename To> |
| 167 | struct is_embedded { see documentation }; |
| 168 | #else |
| 169 | template <typename From, typename To, typename = void> |
| 170 | struct is_embedded; |
| 171 | #endif |
| 172 | }} // end namespace boost::hana |
| 173 | |
| 174 | #endif // !BOOST_HANA_FWD_CORE_TO_HPP |
| 175 | |