// 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 #include #include #include #include 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 struct foo { static void apply(T& t, const U& u) { t.foo(u); } }; namespace boost { namespace type_erasure { template struct concept_interface< ::foo, Base, T, Enable> : Base { typedef void _fun_defined; void foo(typename as_param::type arg) { call(::foo(), *this, arg); } }; template struct concept_interface< ::foo, Base, T, typename Base::_fun_defined> : Base { using Base::foo; void foo(typename as_param::type arg) { call(::foo(), *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 struct bar_concept { static void apply(T& t, const U& u) { bar(t, u); } }; namespace boost { namespace type_erasure { template struct concept_interface< ::bar_concept, Base, T> : Base { friend void bar(typename derived::type& t, typename as_param::type u) { call(::bar_concept(), t, u); } }; template struct concept_interface< ::bar_concept, Base, U, typename boost::disable_if >::type> : Base { using Base::bar; friend void bar(T& t, const typename derived::type& u) { call(::bar_concept(), 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] //]