tag_dispatching.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // Copyright Louis Dionne 2013-2017
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  4. #include <boost/hana/assert.hpp>
  5. #include <boost/hana/core/tag_of.hpp>
  6. #include <boost/hana/integral_constant.hpp>
  7. #include <boost/hana/minus.hpp>
  8. #include <boost/hana/not_equal.hpp>
  9. #include <boost/hana/tuple.hpp>
  10. #include <cstddef>
  11. #include <iostream>
  12. #include <sstream>
  13. namespace hana = boost::hana;
  14. //! [setup]
  15. template <typename Tag>
  16. struct print_impl {
  17. template <typename X>
  18. static void apply(std::ostream&, X const&) {
  19. // possibly some default implementation
  20. }
  21. };
  22. template <typename X>
  23. void print(std::ostream& os, X x) {
  24. using Tag = typename hana::tag_of<X>::type;
  25. print_impl<Tag>::apply(os, x);
  26. }
  27. //! [setup]
  28. //! [vector]
  29. struct vector_tag;
  30. struct vector0 {
  31. using hana_tag = vector_tag;
  32. static constexpr std::size_t size = 0;
  33. };
  34. template <typename T1>
  35. struct vector1 {
  36. T1 t1;
  37. using hana_tag = vector_tag;
  38. static constexpr std::size_t size = 1;
  39. template <typename Index>
  40. auto const& operator[](Index i) const {
  41. static_assert(i == 0u, "index out of bounds");
  42. return t1;
  43. }
  44. };
  45. template <typename T1, typename T2>
  46. struct vector2 {
  47. T1 t1; T2 t2;
  48. using hana_tag = vector_tag;
  49. static constexpr std::size_t size = 2;
  50. // Using Hana as a backend to simplify the example.
  51. template <typename Index>
  52. auto const& operator[](Index i) const {
  53. return *hana::make_tuple(&t1, &t2)[i];
  54. }
  55. };
  56. // and so on...
  57. //! [vector]
  58. //! [customize]
  59. template <>
  60. struct print_impl<vector_tag> {
  61. template <typename vectorN>
  62. static void apply(std::ostream& os, vectorN xs) {
  63. auto N = hana::size_c<vectorN::size>;
  64. os << "[";
  65. N.times.with_index([&](auto i) {
  66. os << xs[i];
  67. if (i != N - hana::size_c<1>) os << ", ";
  68. });
  69. os << "]";
  70. }
  71. };
  72. //! [customize]
  73. #if 0
  74. //! [customize-when]
  75. template <typename Tag>
  76. struct print_impl<Tag, hana::when<Tag represents some kind of sequence>> {
  77. template <typename Seq>
  78. static void apply(std::ostream& os, Seq xs) {
  79. // Some implementation for any sequence
  80. }
  81. };
  82. //! [customize-when]
  83. #endif
  84. int main() {
  85. {
  86. std::stringstream ss;
  87. vector0 v0;
  88. print(ss, v0);
  89. BOOST_HANA_RUNTIME_CHECK(ss.str() == "[]");
  90. }
  91. {
  92. std::stringstream ss;
  93. vector1<int> v1{1};
  94. print(ss, v1);
  95. BOOST_HANA_RUNTIME_CHECK(ss.str() == "[1]");
  96. }
  97. {
  98. std::stringstream ss;
  99. vector2<int, char> v2{1, 'x'};
  100. print(ss, v2);
  101. BOOST_HANA_RUNTIME_CHECK(ss.str() == "[1, x]");
  102. }
  103. }
  104. namespace old_way {
  105. //! [old_way]
  106. void print(std::ostream& os, vector0)
  107. { os << "[]"; }
  108. template <typename T1>
  109. void print(std::ostream& os, vector1<T1> v)
  110. { os << "[" << v.t1 << "]"; }
  111. template <typename T1, typename T2>
  112. void print(std::ostream& os, vector2<T1, T2> v)
  113. { os << "[" << v.t1 << ", " << v.t2 << "]"; }
  114. // and so on...
  115. //! [old_way]
  116. }
  117. namespace preconditions {
  118. //! [preconditions]
  119. template <typename X>
  120. void print(std::ostream& os, X x) {
  121. // **** check some precondition ****
  122. // The precondition only has to be checked here; implementations
  123. // can assume their arguments to always be sane.
  124. using Tag = typename hana::tag_of<X>::type;
  125. print_impl<Tag>::apply(os, x);
  126. }
  127. //! [preconditions]
  128. }
  129. namespace function_objects {
  130. //! [function_objects]
  131. // Defining a function object is only needed once and implementations do not
  132. // have to worry about static initialization and other painful tricks.
  133. struct print_t {
  134. template <typename X>
  135. void operator()(std::ostream& os, X x) const {
  136. using Tag = typename hana::tag_of<X>::type;
  137. print_impl<Tag>::apply(os, x);
  138. }
  139. };
  140. constexpr print_t print{};
  141. //! [function_objects]
  142. static_assert(sizeof(print) || true, "remove unused variable print warning");
  143. }