Boost logo

Boost :

From: Terje Slettebø (tslettebo_at_[hidden])
Date: 2004-09-14 14:25:21

>From: "David Abrahams" <dave_at_[hidden]>

> Terje Slettebø <tslettebo_at_[hidden]> writes:
> > Are you tired of long and incomprehensible error messages when using
> > STL, MPL, or some other modern template library? So am I!
> >
> > template<class Iterator>
> > typename enable_if<is_random_access_iterator<Iterator> >::type
> > sort(Iterator begin, Iterator end)
> > {
> > // ...
> > }
> enable_if doesn't always improve error messages. Sometimes you get a
> long list of candidate functions when what you really wanted was a
> message from inside just one of the overloads that indicates how
> concept conformance was violated.

How can you get a list of candidate functions, if enable_if excludes them
from the overload set? Could you give a code example?

> Isn't that what we've already been discussing in
> ( ?

Yes, and I noted that thread at the end of the posting. However, at least at
the beginning of that thread, only one property was detected,
dereferenceability. I see that it has later been generalised to any
overloadable operator.

I'll come to Daniel Wallin's approach below here (where you mention it), but
I've had a look at Alex Chovanec's is_dereferenceable in Yahoo Files, and it
contains some clever tricks, such as overloading the comma operator to
permit detection of overloaded operators returning void. Definitely one I'd
like to add.

There are also similar facilites as
traits library, although they are not documented, as such detection for all
the overloadable operators is already defined in the library, so the user
shouldn't really have a need for it. Nevertheless, they are found in the
operator_traits/detail/unop.hpp (prefix), unop2.hpp (postfix) and binop.hpp

These headers contain macros such as
BOOST_OT_DETAIL_DEFINE_UNOP_TRAIT(name,op), which again define templates for
detecting the given operator. For example
BOOST_OT_DETAIL_DEFINE_UNOP_TRAIT(has_dereference_op, *) will generate the
template has_dereference_op<T>, which will detect the presence of the
dereference operator for T.

The current version of is_xxxable.hpp in Yahoo Files does seem to have some
problems, when it comes to implicit conversions. Unfortunately, I found that
the same problem exists in the operator traits (has_dereference_op). :) The
following program gives a compiler error for is_dereferenceable:

#include <iostream>
#include "is_dereferenceable.hpp" // Uses is_xxxable.hpp

struct A {};

struct B
  operator A() { return A(); }

A operator*(A) { return A(); }

using namespace boost::detail;

int main()
  std::cout << is_dereferenceable<A>::value << "\n"; // Ok
  std::cout << is_dereferenceable<B>::value << "\n"; // Error, ambiguity
between A and any_conversion_eater

  A a;
  B b;

  *a; // Sure
  *b; // No problem, either; B is implicitly converted to A, which does have
a dereference operator

Also, it didn't have a binary operator detection, or I'd liked to test if
both int + int and int + double (requires promotion) would work (it does
with the operator traits).

> > Other approaches
> > -------------------------
> >
> > About a year ago, there have been proposals/discussion papers for adding
> > support for concepts to the C++ language (see N1510, N1522 and N1536 at
> > Using this,
> > above example could have been written as:
> >
> <snip real concepts>
> Real concepts have the advantage of being able to dispatch to the
> "most-refined" overload.

Yes, that's what I said just below the part you quote above:

>This would also ease implementation of such concept overloading, because it
>would include the concept of concept refinement and "best match".

> > Synopsis
> > -------------
> > The library contains:
> >
> > - 46 operator type traits, covering all the overloadable (and therefore
> > detectable) operators, as well as detection of default constructor, copy
> > constructor and assignment operator.
> >
> > - 37 C++ standard concepts type traits, covering all the concepts of the
> > standard.
> >
> > - 19 Boost.MPL concepts type traits, covering all the documented
concepts of
> > Boost.MPL.
> Things have changed quite a bit since the last release of MPL. Are
> you sure you're up-to-date?

That's a little hard to tell, given that the docs haven't been updated, yet
(at least for the trunk). I've covered what is documented, including the
release notes for the coming Boost 1.32 release, that Aleksey posted a while

> > P.P.S. I've also seen the last days there have been discussion on the
> > list on similar facilities (the "Proposal for 'is_dereferenceable' and
> > templatemetafunctions" thread started by Alex Chovanec).
> > is_dereferenceable<T> is similar to this library's has_dereference_op<T>
> > the operator traits part), except that the latter doesn't test for
> > etc.
> I think the big advantage of Daniel Wallin's last crack at that is
> that it provides the means to *generate* new metafunctions for
> detecting namespace-scope-overloadable functions (including operators)
> via a macro.

I agree that it's a good approach, and as mentioned above, a similar one is
used in the implementation of the operator/concept traits, and which is also
available to users.of the library (they are described in the
"type_traits_ext" part of the docs).

The traits for the C++ standard and MPL concepts is simply provided for
"convenience" (and "proof of concept", nu pun intended. :) ), saving people
from the hard work of defining them all. This is completely analoguous to
the way BCCL provides components for defining your own concept checks, while
also providing concept checks for most of the C++ standard concepts.

Unfortunately, I was unable to get Daniel Wallin's result_check_test.cpp to
compile, as I got the following error on Intel C++ (latest Boost Sandbox was

boost-sandbox\libs\utility\test\result_check_test.cpp(8): error: identifier
"void_result_tag" is undefined
  BOOST_RESULT_CHECK(2, add, operator+, _1 + _2)

> I think providing the automation is probably more
> important than providing a sweeping catalog of individual
> metafunctions, though I could be wrong.

I think you're right. BOOST_OT_DEFINE_UNOP_TRAIT(name, op) demonstrates this
above (just like Alex and Daniel's approach). To show a simple example of
how to build on this, again (using existing traits): Say you have a concept
which requires the types involved to be Assignable and have the "+" and "-"
operators defined for them (including allowing implicit
promotions/conversions). Here's the concept trait:

#include <boost/operator_traits/has_plus_op.hpp>
#include <boost/operator_traits/has_minus_op.hpp>
#include <boost/concept_traits/std/is_assignable.hpp>

template<class T1,class T2>
struct is_my_concept :
    has_plus_op<T1, T2>,
    has_minus_op<T1, T2>
> {};

and you're done.

Note that you may do "concept refinement" by simply including the concept
you refine in the and_<>-list.

> I think I'd rather see the
> concept detection metafunctions in the libraries that define those
> concepts, rather than concentrated in one place...

That's an idea, and as shown above, you can define your own traits. However,
if you already have a library that can detect all the operators, as well as
facilities for detecting member functions, etc., your own implementation can
be rather light-weight.

Alternatively, you might go from "first principles" and define the
is_assignable, has_plus_op, and has_minus_op traits, yourself. However, they
are non-trivial to define, as you have to "filter" the types you test for,
to avoid compilation errors (as Daniel mentioned in a posting, about
specialising for fundamental types, pointers, etc.).



Boost list run by bdawes at, gregod at, cpdaniel at, john at