overload.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // Boost.TypeErasure library
  2. //
  3. // Copyright 2011 Steven Watanabe
  4. //
  5. // Distributed under the Boost Software License Version 1.0. (See
  6. // accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. // $Id$
  10. #include <boost/type_erasure/concept_interface.hpp>
  11. #include <boost/type_erasure/param.hpp>
  12. #include <boost/type_erasure/derived.hpp>
  13. #include <boost/type_erasure/is_placeholder.hpp>
  14. #include <boost/utility/enable_if.hpp>
  15. namespace mpl = boost::mpl;
  16. using namespace boost::type_erasure;
  17. //[overload1
  18. /*`
  19. __concept_interface allows us to inject arbitrary declarations
  20. into an __any. This is very flexible, but there are some pitfalls
  21. to watch out for. Sometimes we want to use the same concept several
  22. times with different parameters. Specializing __concept_interface
  23. in a way that handles overloads correctly is a bit tricky.
  24. Given a concept foo, we'd like the following to work:
  25. ``
  26. any<
  27. mpl::vector<
  28. foo<_self, int>,
  29. foo<_self, double>,
  30. copy_constructible<>
  31. >
  32. > x = ...;
  33. x.foo(1); // calls foo(int)
  34. x.foo(1.0); // calls foo(double)
  35. ``
  36. Because __concept_interface creates a linear
  37. inheritance chain, without some extra work,
  38. one overload of foo will hide the other.
  39. Here are the techniques that I found work reliably.
  40. For member functions I couldn't find a way to
  41. avoid using two specializations.
  42. */
  43. template<class T, class U>
  44. struct foo
  45. {
  46. static void apply(T& t, const U& u) { t.foo(u); }
  47. };
  48. namespace boost {
  49. namespace type_erasure {
  50. template<class T, class U, class Base, class Enable>
  51. struct concept_interface< ::foo<T, U>, Base, T, Enable> : Base
  52. {
  53. typedef void _fun_defined;
  54. void foo(typename as_param<Base, const U&>::type arg)
  55. {
  56. call(::foo<T, U>(), *this, arg);
  57. }
  58. };
  59. template<class T, class U, class Base>
  60. struct concept_interface< ::foo<T, U>, Base, T, typename Base::_fun_defined> : Base
  61. {
  62. using Base::foo;
  63. void foo(typename as_param<Base, const U&>::type arg)
  64. {
  65. call(::foo<T, U>(), *this, arg);
  66. }
  67. };
  68. }
  69. }
  70. /*`
  71. This uses SFINAE to detect whether a using declaration is
  72. needed. Note that the fourth argument of __concept_interface
  73. is a dummy parameter which is always void and is
  74. intended to be used for SFINAE.
  75. Another solution to the problem that I've used
  76. in the past is to inject a dummy declaration of `fun`
  77. and always put in a using declaration. This is an
  78. inferior solution for several reasons. It requires an
  79. extra interface to add the dummy overload. It also
  80. means that `fun` is always overloaded, even if the
  81. user only asked for one overload. This makes it
  82. harder to take the address of fun.
  83. Note that while using SFINAE requires some code
  84. to be duplicated, the amount of code that has to
  85. be duplicated is relatively small, since the implementation
  86. of __concept_interface is usually a one liner. It's
  87. a bit annoying, but I believe it's an acceptable cost
  88. in lieu of a better solution.
  89. */
  90. //]
  91. //[overload2
  92. /*`
  93. For free functions you can use inline friends.
  94. */
  95. template<class T, class U>
  96. struct bar_concept
  97. {
  98. static void apply(T& t, const U& u) { bar(t, u); }
  99. };
  100. namespace boost {
  101. namespace type_erasure {
  102. template<class T, class U, class Base>
  103. struct concept_interface< ::bar_concept<T, U>, Base, T> : Base
  104. {
  105. friend void bar(typename derived<Base>::type& t, typename as_param<Base, const U&>::type u)
  106. {
  107. call(::bar_concept<T, U>(), t, u);
  108. }
  109. };
  110. template<class T, class U, class Base>
  111. struct concept_interface< ::bar_concept<T, U>, Base, U, typename boost::disable_if<is_placeholder<T> >::type> : Base
  112. {
  113. using Base::bar;
  114. friend void bar(T& t, const typename derived<Base>::type& u)
  115. {
  116. call(::bar_concept<T, U>(), t, u);
  117. }
  118. };
  119. }
  120. }
  121. /*`
  122. Basically we have to specialize __concept_interface once for
  123. each argument to make sure that an overload is injected into
  124. the first argument that's a placeholder.
  125. As you might have noticed, the argument types are a bit tricky.
  126. In the first specialization, the first argument uses __derived
  127. instead of __as_param. The reason for this is that if we used
  128. __as_param, then we could end up violating the one definition
  129. rule by defining the same function twice. Similarly, we use
  130. SFINAE in the second specialization to make sure that bar is
  131. only defined once when both arguments are placeholders. It's
  132. possible to merge the two specializations with a bit of metaprogramming,
  133. but unless you have a lot of arguments, it's probably not
  134. worth while.
  135. */
  136. //]
  137. //[overload
  138. //` (For the source of the examples in this section see
  139. //` [@boost:/libs/type_erasure/example/overload.cpp overload.cpp])
  140. //` [overload1]
  141. //` [overload2]
  142. //]