Boost logo

Boost :

From: Brian McNamara (lorgon_at_[hidden])
Date: 2003-11-13 22:45:01


On Thu, Nov 13, 2003 at 04:54:20PM -1000, David Abrahams wrote:
> "Brock Peabody" <brock.peabody_at_[hidden]> writes:
> > template <typename T> T* clone(const T& t) {
> > return mpl::if_<
> > has_clone_function<T>,
> > use_clone_function,
> > use_copy_constructor
> > >::type::clone(t);
> > }
>
> This sort of thing really worries me in generic code, because the name
> alone is not enough to identify the semantics. It's one thing to say,
> "if this thing has a clone function AND its signature contains a
> special type that you can only know about if you also know about the
> way my library looks for clone functions, then...", but when you just
> check for a clone function as you do above, you're relying on everyone
> having an agreement about the meaning of "clone".
>
> OK, so maybe clone is more likely to be agreed upon than the semantics
> of most other member function names. I hope you get my point, though.
> It's easy to create really broken "generic" designs with these sorts of
> tests. You have to use them very carefully.

"Me too."

In my opinion, "named conformance" is the right way to design most
interfaces, whereas "structural conformance" (as above) is the wrong
way. What you really want to say is

   template <typename T> T* clone(const T& t) {
      return mpl::if_<
         is_clonable<T>,
         use_clone_function,
         use_copy_constructor
>::type::clone(t);
   }

where is_clonable is a metafunction which tests not only the structural
conformance (as suggested above), but also named conformance. Some
human should have to explicitly say that T is indeed a clonable (e.g. it
has the right semantics to match the concept). This can be done in a
variety of ways, the most popular probably being via specialization:

   // One possible implementation
   template <class T> is_a_clonable
   { static const bool value = false; };

   ...
   // I hereby declare that Foo meets the semantic requirements:
   template <> is_a_clonable<Foo>
   { static const bool value = true; };

Then the logic for "is_clonable<T>" is to check both of

   has_clone_function<T> // henceforth abbreviated "structural"
   is_a_clonable<T> // henceforth abbreviated "named"

and use the logic

   if( named && structural )
      true
   else if( named )
      cause a useful compile-time error message which tries to alert the
      author of "T" that she declared that T met the concept, but in fact
      she failed to fulfill all of its structural requirements
   else
      false

See "Static Interfaces in C++" at
   http://www.oonumerics.org/tmpw00/
for a (now dated) longer version of my opinion on the topic. Perhaps I
should try to reimplement my ideas atop MPL (using, as appropriate, the
new knowledge of how to detect structural conformance).

-- 
-Brian McNamara (lorgon_at_[hidden])

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk