tag_of.hpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /*!
  2. @file
  3. Forward declares `boost::hana::tag_of` and `boost::hana::tag_of_t`.
  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_TAG_OF_HPP
  9. #define BOOST_HANA_FWD_CORE_TAG_OF_HPP
  10. #include <boost/hana/config.hpp>
  11. BOOST_HANA_NAMESPACE_BEGIN
  12. //! @ingroup group-core
  13. //! %Metafunction returning the tag associated to `T`.
  14. //!
  15. //! There are several ways to specify the tag of a C++ type. If it's a
  16. //! user-defined type, one can define a nested `hana_tag` alias:
  17. //! @code
  18. //! struct MyUserDefinedType {
  19. //! using hana_tag = MyTag;
  20. //! };
  21. //! @endcode
  22. //!
  23. //! Sometimes, however, the C++ type can't be modified (if it's in a
  24. //! foreign library) or simply can't have nested types (if it's not a
  25. //! struct or class). In those cases, using a nested alias is impossible
  26. //! and so ad-hoc customization is also supported by specializing
  27. //! `tag_of` in the `boost::hana` namespace:
  28. //! @code
  29. //! struct i_cant_modify_this;
  30. //!
  31. //! namespace boost { namespace hana {
  32. //! template <>
  33. //! struct tag_of<i_cant_modify_this> {
  34. //! using type = MyTag;
  35. //! };
  36. //! }}
  37. //! @endcode
  38. //!
  39. //! `tag_of` can also be specialized for all C++ types satisfying some
  40. //! boolean condition using `when`. `when` accepts a single compile-time
  41. //! boolean and enables the specialization of `tag_of` if and only if
  42. //! that boolean is `true`. This is similar to the well known C++ idiom
  43. //! of using a dummy template parameter with `std::enable_if` and relying
  44. //! on SFINAE. For example, we could specify the tag of all
  45. //! `fusion::vector`s by doing:
  46. //! @code
  47. //! struct BoostFusionVector;
  48. //!
  49. //! namespace boost { namespace hana {
  50. //! template <typename T>
  51. //! struct tag_of<T, when<
  52. //! std::is_same<
  53. //! typename fusion::traits::tag_of<T>::type,
  54. //! fusion::traits::tag_of<fusion::vector<>>::type
  55. //! >::value
  56. //! >> {
  57. //! using type = BoostFusionVector;
  58. //! };
  59. //! }}
  60. //! @endcode
  61. //!
  62. //! Also, when it is not specialized and when the given C++ type does not
  63. //! have a nested `hana_tag` alias, `tag_of<T>` returns `T` itself. This
  64. //! makes tags a simple extension of normal C++ types. This is _super_
  65. //! useful, mainly for two reasons. First, this allows Hana to adopt a
  66. //! reasonable default behavior for some operations involving types that
  67. //! have no notion of tags. For example, Hana allows comparing with `equal`
  68. //! any two objects for which a valid `operator==` is defined, and that
  69. //! without any work on the user side. Second, it also means that you can
  70. //! ignore tags completely if you don't need their functionality; just use
  71. //! the normal C++ type of your objects and everything will "just work".
  72. //!
  73. //! Finally, also note that `tag_of<T>` is always equivalent to `tag_of<U>`,
  74. //! where `U` is the type `T` after being stripped of all references and
  75. //! cv-qualifiers. This makes it unnecessary to specialize `tag_of` for
  76. //! all reference and cv combinations, which would be a real pain. Also,
  77. //! `tag_of` is required to be idempotent. In other words, it must always
  78. //! be the case that `tag_of<tag_of<T>::%type>::%type` is equivalent to
  79. //! `tag_of<T>::%type`.
  80. //!
  81. //! > __Tip 1__\n
  82. //! > If compile-time performance is a serious concern, consider
  83. //! > specializing the `tag_of` metafunction in Hana's namespace.
  84. //! > When unspecialized, the metafunction has to use SFINAE, which
  85. //! > tends to incur a larger compile-time overhead. For heavily used
  86. //! > templated types, this can potentially make a difference.
  87. //!
  88. //! > __Tip 2__\n
  89. //! > Consider using `tag_of_t` alias instead of `tag_of`, which
  90. //! > reduces the amount of typing in dependent contexts.
  91. //!
  92. //!
  93. //! Example
  94. //! -------
  95. //! @include example/core/tag_of.cpp
  96. #ifdef BOOST_HANA_DOXYGEN_INVOKED
  97. template <typename T, optional when-based enabler>
  98. struct tag_of { unspecified };
  99. #else
  100. template <typename T, typename = void>
  101. struct tag_of;
  102. #endif
  103. //! @ingroup group-core
  104. //! Alias to `tag_of<T>::%type`, provided for convenience.
  105. //!
  106. //!
  107. //! Example
  108. //! -------
  109. //! @include example/core/tag_of_t.cpp
  110. template <typename T>
  111. using tag_of_t = typename hana::tag_of<T>::type;
  112. BOOST_HANA_NAMESPACE_END
  113. #endif // !BOOST_HANA_FWD_CORE_TAG_OF_HPP