struct.hpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /*!
  2. @file
  3. Forward declares `boost::hana::Struct`.
  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_CONCEPT_STRUCT_HPP
  9. #define BOOST_HANA_FWD_CONCEPT_STRUCT_HPP
  10. #include <boost/hana/config.hpp>
  11. BOOST_HANA_NAMESPACE_BEGIN
  12. //! @ingroup group-concepts
  13. //! @defgroup group-Struct Struct
  14. //! The `Struct` concept represents `struct`-like user-defined types.
  15. //!
  16. //! The `Struct` concept allows restricted compile-time reflection over
  17. //! user-defined types. In particular, it allows accessing the names of
  18. //! the members of a user-defined type, and also the value of those
  19. //! members. `Struct`s can also be folded, searched and converted to
  20. //! some types of containers, where more advanced transformations can
  21. //! be performed.
  22. //!
  23. //! While all types can _in theory_ be made `Struct`s, only a subset of
  24. //! them are actually interesting to see as such. More precisely, it is
  25. //! only interesting to make a type a `Struct` when it is conceptually
  26. //! a C++ `struct`, i.e. a mostly dumb aggregate of named data. The way
  27. //! this data is accessed is mostly unimportant to the `Struct` concept;
  28. //! it could be through getters and setters, through public members,
  29. //! through non-member functions or it could even be generated on-the-fly.
  30. //! The important part, which is made precise below, is that those accessor
  31. //! methods should be move-independent.
  32. //!
  33. //! Another way to see a `Struct` is as a map where the keys are the names
  34. //! of the members and the values are the values of those members. However,
  35. //! there are subtle differences like the fact that one can't add a member
  36. //! to a `Struct`, and also that the order of the members inside a `Struct`
  37. //! plays a role in determining the equality of `Struct`s, which is not
  38. //! the case for maps.
  39. //!
  40. //!
  41. //! Minimal complete definition
  42. //! ---------------------------
  43. //! `accessors`
  44. //!
  45. //! A model of `Struct` is created by specifying a sequence of key/value
  46. //! pairs with the `accessors` function. The first element of a pair in
  47. //! this sequence represents the "name" of a member of the `Struct`, while
  48. //! the second element is a function which retrieves this member from an
  49. //! object. The "names" do not have to be in any special form; they just
  50. //! have to be compile-time `Comparable`. For example, it is common to
  51. //! provide "names" that are `hana::string`s representing the actual names
  52. //! of the members, but one could provide `hana::integral_constant`s just
  53. //! as well. The values must be functions which, when given an object,
  54. //! retrieve the appropriate member from it.
  55. //!
  56. //! There are several ways of providing the `accessors` method, some of
  57. //! which are more flexible and others which are more convenient. First,
  58. //! one can define it through tag-dispatching, as usual.
  59. //! @snippet example/struct.mcd.tag_dispatching.cpp main
  60. //!
  61. //! Secondly, it is possible to provide a nested `hana_accessors_impl`
  62. //! type, which should be equivalent to a specialization of
  63. //! `accessors_impl` for tag-dispatching. However, for a type `S`, this
  64. //! technique only works when the data type of `S` is `S` itself, which
  65. //! is the case unless you explicitly asked for something else.
  66. //! @snippet example/struct.mcd.nested.cpp main
  67. //!
  68. //! Finally, the most convenient (but least flexible) option is to use
  69. //! the `BOOST_HANA_DEFINE_STRUCT`, the `BOOST_HANA_ADAPT_STRUCT` or the
  70. //! `BOOST_HANA_ADAPT_ADT` macro, which provide a minimal syntactic
  71. //! overhead. See the documentation of these macros for details on how
  72. //! to use them.
  73. //!
  74. //! Also note that it is not important that the accessor functions retrieve
  75. //! an actual member of the struct (e.g. `x.member`). Indeed, an accessor
  76. //! function could call a custom getter or even compute the value of the
  77. //! member on the fly:
  78. //! @snippet example/struct.custom_accessor.cpp main
  79. //!
  80. //! The only important thing is that the accessor functions are
  81. //! move-independent, a notion which is defined below.
  82. //!
  83. //!
  84. //! @anchor move-independence
  85. //! Move-independence
  86. //! -----------------
  87. //! The notion of move-independence presented here defines rigorously
  88. //! when it is legitimate to "double-move" from an object.
  89. //!
  90. //! A collection of functions `f1, ..., fn` sharing the same domain is
  91. //! said to be _move-independent_ if for every fresh (not moved-from)
  92. //! object `x` in the domain, any permutation of the following statements
  93. //! is valid and leaves the `zk` objects in a fresh (not moved-from) state:
  94. //! @code
  95. //! auto z1 = f1(std::move(x));
  96. //! ...
  97. //! auto zn = fn(std::move(x));
  98. //! @endcode
  99. //!
  100. //! @note
  101. //! In the special case where some functions return objects that can't be
  102. //! bound to with `auto zk =` (like `void` or a non-movable, non-copyable
  103. //! type), just pretend the return value is ignored.
  104. //!
  105. //! Intuitively, this ensures that we can treat `f1, ..., fn` as
  106. //! "accessors" that decompose `x` into independent subobjects, and
  107. //! that do so without moving from `x` more than that subobject. This
  108. //! is important because it allows us to optimally decompose `Struct`s
  109. //! into their subparts inside the library.
  110. //!
  111. //!
  112. //! Laws
  113. //! ----
  114. //! For any `Struct` `S`, the accessors in the `accessors<S>()` sequence
  115. //! must be move-independent, as defined above.
  116. //!
  117. //!
  118. //! Refined concepts
  119. //! ----------------
  120. //! 1. `Comparable` (free model)\n
  121. //! `Struct`s are required to be `Comparable`. Specifically, two `Struct`s
  122. //! of the same data type `S` must be equal if and only if all of their
  123. //! members are equal. By default, a model of `Comparable` doing just that
  124. //! is provided for models of `Struct`. In particular, note that the
  125. //! comparison of the members is made in the same order as they appear in
  126. //! the `hana::members` sequence.
  127. //! @include example/struct/comparable.cpp
  128. //!
  129. //! 2. `Foldable` (free model)\n
  130. //! A `Struct` can be folded by considering it as a list of pairs each
  131. //! containing the name of a member and the value associated to that
  132. //! member, in the same order as they appear in the `hana::members`
  133. //! sequence. By default, a model of `Foldable` doing just that is
  134. //! provided for models of the `Struct` concept.
  135. //! @include example/struct/foldable.cpp
  136. //! Being a model of `Foldable` makes it possible to turn a `Struct`
  137. //! into basically any `Sequence`, but also into a `hana::map` by simply
  138. //! using the `to<...>` function!
  139. //! @include example/struct/to.cpp
  140. //!
  141. //! 3. `Searchable` (free model)\n
  142. //! A `Struct` can be searched by considering it as a map where the keys
  143. //! are the names of the members of the `Struct`, and the values are the
  144. //! members associated to those names. By default, a model of `Searchable`
  145. //! is provided for any model of the `Struct` concept.
  146. //! @include example/struct/searchable.cpp
  147. template <typename S>
  148. struct Struct;
  149. BOOST_HANA_NAMESPACE_END
  150. #endif // !BOOST_HANA_FWD_CONCEPT_STRUCT_HPP