$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [boost] [type_erasure] Review started (July 18-27, 2012)
From: Fabio Fracassi (f.fracassi_at_[hidden])
Date: 2012-07-30 02:30:50
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