|
Boost : |
From: Jeremiah Willcock (jewillco_at_[hidden])
Date: 2003-08-21 10:30:00
On Thu, 21 Aug 2003, Peter Dimov wrote:
> David Abrahams wrote:
> > "Peter Dimov" <pdimov_at_[hidden]> writes:
> >
> >> David Abrahams wrote:
> >>> Jaakko Jarvi <jajarvi_at_[hidden]> writes:
> >>>
> >>>> 4. Non-SFINAE compilers
(snip)
> >>>
> >>> Can you justify that choice a bit? In the applications where I've
> >>> used it, no-op behavior provides good gradual degradation in
> >>> functionality (I don't have a strong opinion though).
In general, having enable_if silently succeed when it shouldn't seems
dangerous. Programmers will write code for compilers that support SFINAE,
and their code appears to work on non-SFINAE compilers as well, but the
overloading behavior can be different. Peter's example below is a good
demonstration of this. Thus, we would rather the programmer explicitly
write code to handle the non-SFINAE compiler case.
> >> template<class X, class Y>
> >> typename enable_if<is_expression<X>::value ||
> >> is_expression<Y>::value, ...>::type
> >> operator+(X const & x, Y const & y);
> >
> > Yes, I have precisely such a situation (see
> > boost/python/object_operators.hpp). I put those in an isolated
> > namespace with the "expression" template, which gets us 90% of the
> > way there. The last 10% is given by enable_if, when available.
>
> In some cases it is not possible to rely on ADL to find op+. Consider the
> case _1 + 5. ADL works if the _1 refers to your own placeholder, defined in
> boost::lambda (for instance.) But the _1 from std::placeholders won't work
> unless you bring operator+ in scope. In short, sometimes you want the
> operator to match types that aren't your own.
>
> I'm not sure how important this is, though; no strong opinion from me
> either.
There are some cases in which a test being always enabled will cause a
function call to succeed, but with a different overload chosen than will
be chosen by SFINAE. An example of this is:
template <class Derived>
struct vector_tag {}; // Barton-Nackman base class
struct my_vector: public vector_tag<my_vector> { ... };
template <class T>
double norm(const vector_tag<T>& vec) { ... } // Vector case
template <class T>
typename enable_if<boost::is_arithmetic<T>, double>::type
norm(const T& scalar) { ... } // Scalar case
A call to norm() with an object of type my_vector will correctly use the
vector case in a compiler supporting SFINAE, but will instead use the
scalar case (without an error message at the call site) in a compiler
where enable_if is ignored.
Cheers,
Jeremiah Willcock and Jaakko Järvi
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk