Boost logo

Boost :

From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2002-12-05 18:49:00


----- Original Message -----
From: "David B. Held" <dheld_at_[hidden]>

> "Jon Kalb" <jonkalb_at_[hidden]> wrote in message
>
news:1BF6E16701F67A459A4D199880AF910301FA2770_at_svc-msg-01.northamerica.corp.m
> icrosoft.com...
> > [...]
> > Vandevoorde and Josuttis call it SFINAE, "substitution failute is not an
> > error."
>
> Ah, I've heard of this, but didn't realize what it was all about.
>
> > In "C++ Templates: The Complete Guide" (Recommended), they give
> > this example on pages 106-107:
> >
> > typedef char RT1;
> > typedef struct {char a[2];} RT2;
> > template<typename T> RT1 test(typename T::X const*);
> > template<typename T> RT2 test(...);
> >
> > #define type_has_member_type_X(T) \
> > (sizeof(test<T>(0) == 1)
>
> This is cool. What compilers are known to support it?

Comeau C++ certainly supports it (what a surprise...). BTW, this is nothing
new. It was discovered a while back based on an "is_enum" implementation,
which was converted to an "is_class" implementation, which, finally, was
converted to a "has_member_..." implementation. (I think by Rani Sharoni,
but I'm not sure.) The bad part about it is that there is no way, given the
nature of the solution, to parametize the member name.

Also, SFINAE, according to the standard does not apply to expression errors,
and is very unclear about what happens, for example in the code above, if
"X" is a template instead of a regular type.

I talked to Daveed Vandevoorde about this issue this past week. Supposedly,
the SFINAE principle used to be very broad, but compilers were having
difficulty implementing it "robustly," so they (as in core-3) dumbed it down
to only include the "list of ways that deduction/substitution can fail" in
14.8.2. This list is, in effect, a list of negatives--which IMO is a bad
idea. Apparently, they've added things to this list in each of the last
three core-3 meetings (or whatever they are).

Personally, I believe the SFINAE principle should be significantly broader.
The original argument about the "difficulty" of a robust implementation is
pretty bogus considering that most compilers won't handle just the invalid
type-creation attempts listed in 14.8.2 anyway. Also, the line between
"invalid type" and "invalid expression" is significantly blurred because of
the sizeof and typeid operators (not to mention "invalid templates").
Consider again how brittle the above might be:

template<class T> char test(typename T::X const*);
template<class T> char (& test(...))[2];

#define has_member_type_X(T) \
    (sizeof( test<T>(0) ) == 1)

struct Y {
    template<class> struct X { };
};

has_member_type_X(Y) // ?

Paul Mensonides


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