
AMDG On 07/29/2012 12:28 PM, Fabio Fracassi wrote:
b. creating custom concepts/concept interfaces.
Consider this paragraph as dreaming out loud. I like the way Steven solved the problem of defining concepts but I still like it to be easier, because I believe that how easy it is to define concepts is the key to widespread adoption. Ideally it should not be more complex to define a concept than to define a (virtual) interface. My ideal solution would be able to do this:
struct int_container_concept { //... void push_back(int) = 0; size_t size() = 0; // b.2 //... };
void legacy_func(int_container_concept& c); // b.1
BOOST_CREATE_CONCEPT(int_container_concept);
void test() std::vector<int> v = /*filles somehow*/; any<int_container_concept> con = v;
legacy_func(con); }
I know that it is impossible to implement the BOOST_CREATE_CONCEPT macro in the above example without language support. So until we get compile time reflection in c++ we need to live with the additional boilerplate in some way. In the "Design" section Steven explains that to scrap the boilerplate he departed from defining the user facing interface using abstract classes. My concern with this departure is that it is quite different, and not directly compatible. There are two things type erasures concepts cannot do:
b.1. I cannot use a concept without using any<>. (i.e. the legacy_func marked above would need to take an any<int_container_concept>& instead) This might be a deal-breaker for some users of the library.
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.
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. In Christ, Steven Watanabe