123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- // Boost.TypeErasure library
- //
- // Copyright 2011 Steven Watanabe
- //
- // Distributed under the Boost Software License Version 1.0. (See
- // accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- //
- // $Id$
- #include <boost/type_erasure/concept_interface.hpp>
- #include <boost/type_erasure/param.hpp>
- #include <boost/type_erasure/derived.hpp>
- #include <boost/type_erasure/is_placeholder.hpp>
- #include <boost/utility/enable_if.hpp>
- namespace mpl = boost::mpl;
- using namespace boost::type_erasure;
- //[overload1
- /*`
- __concept_interface allows us to inject arbitrary declarations
- into an __any. This is very flexible, but there are some pitfalls
- to watch out for. Sometimes we want to use the same concept several
- times with different parameters. Specializing __concept_interface
- in a way that handles overloads correctly is a bit tricky.
- Given a concept foo, we'd like the following to work:
- ``
- any<
- mpl::vector<
- foo<_self, int>,
- foo<_self, double>,
- copy_constructible<>
- >
- > x = ...;
- x.foo(1); // calls foo(int)
- x.foo(1.0); // calls foo(double)
- ``
- Because __concept_interface creates a linear
- inheritance chain, without some extra work,
- one overload of foo will hide the other.
- Here are the techniques that I found work reliably.
-
- For member functions I couldn't find a way to
- avoid using two specializations.
- */
- template<class T, class U>
- struct foo
- {
- static void apply(T& t, const U& u) { t.foo(u); }
- };
- namespace boost {
- namespace type_erasure {
- template<class T, class U, class Base, class Enable>
- struct concept_interface< ::foo<T, U>, Base, T, Enable> : Base
- {
- typedef void _fun_defined;
- void foo(typename as_param<Base, const U&>::type arg)
- {
- call(::foo<T, U>(), *this, arg);
- }
- };
- template<class T, class U, class Base>
- struct concept_interface< ::foo<T, U>, Base, T, typename Base::_fun_defined> : Base
- {
- using Base::foo;
- void foo(typename as_param<Base, const U&>::type arg)
- {
- call(::foo<T, U>(), *this, arg);
- }
- };
- }
- }
- /*`
- This uses SFINAE to detect whether a using declaration is
- needed. Note that the fourth argument of __concept_interface
- is a dummy parameter which is always void and is
- intended to be used for SFINAE.
- Another solution to the problem that I've used
- in the past is to inject a dummy declaration of `fun`
- and always put in a using declaration. This is an
- inferior solution for several reasons. It requires an
- extra interface to add the dummy overload. It also
- means that `fun` is always overloaded, even if the
- user only asked for one overload. This makes it
- harder to take the address of fun.
- Note that while using SFINAE requires some code
- to be duplicated, the amount of code that has to
- be duplicated is relatively small, since the implementation
- of __concept_interface is usually a one liner. It's
- a bit annoying, but I believe it's an acceptable cost
- in lieu of a better solution.
- */
- //]
- //[overload2
- /*`
- For free functions you can use inline friends.
- */
- template<class T, class U>
- struct bar_concept
- {
- static void apply(T& t, const U& u) { bar(t, u); }
- };
- namespace boost {
- namespace type_erasure {
- template<class T, class U, class Base>
- struct concept_interface< ::bar_concept<T, U>, Base, T> : Base
- {
- friend void bar(typename derived<Base>::type& t, typename as_param<Base, const U&>::type u)
- {
- call(::bar_concept<T, U>(), t, u);
- }
- };
- template<class T, class U, class Base>
- struct concept_interface< ::bar_concept<T, U>, Base, U, typename boost::disable_if<is_placeholder<T> >::type> : Base
- {
- using Base::bar;
- friend void bar(T& t, const typename derived<Base>::type& u)
- {
- call(::bar_concept<T, U>(), t, u);
- }
- };
- }
- }
- /*`
- Basically we have to specialize __concept_interface once for
- each argument to make sure that an overload is injected into
- the first argument that's a placeholder.
- As you might have noticed, the argument types are a bit tricky.
- In the first specialization, the first argument uses __derived
- instead of __as_param. The reason for this is that if we used
- __as_param, then we could end up violating the one definition
- rule by defining the same function twice. Similarly, we use
- SFINAE in the second specialization to make sure that bar is
- only defined once when both arguments are placeholders. It's
- possible to merge the two specializations with a bit of metaprogramming,
- but unless you have a lot of arguments, it's probably not
- worth while.
- */
- //]
- //[overload
- //` (For the source of the examples in this section see
- //` [@boost:/libs/type_erasure/example/overload.cpp overload.cpp])
- //` [overload1]
- //` [overload2]
- //]
|