
On 7/30/12 2:27 AM, Steven Watanabe wrote:
If you have an abstract base for your legacy interface, you can do this:
template<class T = _self> struct legacy_concept : mpl::vector<...> {};
namespace boost { namespace type_erasure {
template<class T, class Base> struct concept_interface<legacy_concept<T>, Base, T> : Base, legacy_base { // implement legacy_base methods };
}}
Now any<legacy_concept<> > is derived from legacy_base.
Of course, once you've written all this out, you don't gain much over just using:
template<class T> struct legacy_adapter : legacy_base { // constructors and forwarding T impl_; };
which is probably easier to understand. The only thing you gain is the ability to compose with other concepts.
Which is a quite significant win imo.
b.2. I cannot define a concept that has more than one function directly, i.e. I have to define concepts for push_back and size and then compose them (in this case 35 lines of code). This is of course mainly an issue of syntactic sugar, but in Stevens concept definition boiler plate and interface information (member name, arguments, composition lists) are intermixed.
I seem to recall that there was some discussion about having some macros to simplify the boilerplate. I think something along the lines of
BOOST_CREATE_CONCEPT(container_concept, typename T, (void (push_back, T), void (size)) )
wouldn't be too bad.
I rather dislike complex macros like this.
I am non to fond of them either. In this case though it makes the code much cleaner, consider a syntax like above or similar (haven't checked whether this is even possible, my PP foo is not to good) to this: BOOST_CREATE_CONCEPT(push_back, typename T, MEMBER push_back (void (T)) ) concisely gives you all the information (concept name, member func name and signature) a user of this concept needs. In contrast to spelling it out template<class C, class T> // < Part I of the signature struct push_back { // < Concept name here static void apply(C& cont, const T& arg) { cont.push_back(arg); } // the rest of the signature is hidden somewhere in the apply // but never explicitly spelled out }; namespace boost { namespace type_erasure { // lots of duplicated information and unrelated details to // (mis)understand and get wrong template<class C, class T, class Base> struct concept_interface< ::push_back<C, T>, Base, C> : Base { void push_back(typename rebind_any<Base, const T&>::type arg) { call(::push_back<C, T>(), *this, arg); } }; } } Writing this is not to onerous, but (quickly) reading code that uses it ... regards Fabio