to.hpp 7.1 KB

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