Topic: SFINAE anomaly


Author: =3D?ISO-8859-1?Q?Daniel_Kr=3DFCgler?=3D <daniel.kruegler@googlemail.c=.om>
Date: Mon, 19 Jul 2010 17:21:05 CST
Raw View
On 19 Jul., 20:19, Edward Diener <eldie...@tropicsoft.invalid> wrote:
> On 7/18/2010 5:27 PM, Daniel Kr=FCgler wrote:
>
> > I think this is clearly a compiler defect.
>
> Is it a compiler defect under the C++03 compiler using SFINAE, or are
> you saying it is a compiler defect under the C++0x extended SFINAE ? If
> it is a compiler defect only under the C++0x extended SFINAE then it is
> quite possible that the three versions of compilers I have tested this
> under do not yet implement the C++0x extended SFINAE.

I ignored C++03 in my discussion because you already mentioned
"extended SFINAE" rules, which are not available within C++03.
Looking at the C++03 rules I would say that the wording is not
really clear here. A weak interpretation of 14.8.2/2 would include
your example, a strong interpretation would not. The part of the
wording which can be interpreted to apply is bullet 2:

=97 The specified template arguments must match the template
parameters in kind (i.e., type, nontype, template), and there must
not be more arguments than there are parameters; otherwise type
deduction fails.

The problem with the C++03 wording is that it describes are
individual deduction failure cases in a long sub-bullet list below
bullet 3. Your particular situation is not part of the list.
The difference in C++0x is, that the individual list is gone and
the rule is no simply that only types (and expressions) in the
"immediate context" occurring in the function signature (return
type, parameters) are considered. I described that in a lax
way as "top-level types".

> > The new rules clearly say that a invalid type occurring on top
> > level has to be silently ignored.
>
> The phrase "invalid type occurring on top level" appears to be yours,
> and not in the working draft for the standard.

Sure, it was just a non-normative description of the normative
wording that I quoted later.

> > This is essentially satisfied
> > for your snippet. Situations which are *not* covered, are
> > those where instantiation errors occur *within* the type - this
> > doesn't happen here.
>
> I admit I was following the topic athttp://
www.boostcon.com/community/wiki/show/ExtendedSFINAE/, and not
> attempting to understand what the working draft of the C++0x standard
> says, where my search for SFINAE yielded nothing.

Exactly, similar to my "top-level-type" wording, the term SFINAE does
not officially exist in the standard, but it nonetheless became a
non-normative technical term in C++ discussions (and your thread
title contains this non-normative term as well).

> It is explained at that web page that the one of the differences between
> the previous way that SFINAE worked is that "the extended SFINAE rules
> of C++0x generalize SFINAE to work with arbitrary expressions", where I
> did not think that "typename U1::template M<U2, U3>*" was such an
> expression; and where it says that:
>
> 'There are two classes of errors for which SFINAE still does not apply:
>
>     1. If the type-checking failure is due an access violation (e.g., x
> + y resolves to a private operator+), that error is a "hard" error that
> does not invoke SFINAE.

Correct (and we don't have it in your example).

>     2. If the type-checking failure occurs within the instantiation of a
> class template or in the body of a function template, that error is a
> "hard" error that does not invoke SFINAE.'

Also correct. A simple example for such a "hard error" can be
constructed, if we change my revised example as follows:

struct A {
 template <class T>
 struct M {
   M(int, T = T()){}
 };
};

template<class T1, class T2 = void>
struct B {
 template<class U1, class U2>
 static char test(typename U1::template M<U2>);

 template<class, class>
 static char (&test(...))[2];

 static const bool value = sizeof(test<T1, T2>(0)) == 1;

};

B<A> b;

static_assert(!B<A>::value, "Ouch");

This time we might also expect that this should also be well-
formed, relying on the assumption that a function parameter
of type void cannot be valid. But this is a error that happens
"within" A::M<void> and not at the immediate type occurring
in the function declaration

 template<class U1, class U2>
 char test(typename U1::template M<U2>);

> In this case I did not know if the second exception applied because the
> phrase "within the instantiation of a class template" could or could not
> apply to the top level matching of template parameters. If I have:
>
> template <class X> struct Y { };
>
> and the instantiation of the template with:
>
> Y<someType,someOtherType> z;
>
> one could or could not interpret the "within instantiation of the class
> template" as including the matching of template parameters.
> > FCD 14.8.2/7+8:

The point is that the involved type shows up directly in the
function declaration. My loose "top-level" term was supposed to
refer to this immediately occurring type. Another good non-SFINAE
example is this one:

template<typename T>
struct indirect {
 typedef typename T::type type;
};

template<class T>
struct B {
 template<class U>
 static char test(typename indirect<T>::type);

 template<class>
 static char (&test(...))[2];

 static const bool value = sizeof(test<T>(0)) == 1;
};

struct S {
 typedef int type;
};

static_assert(B<S>::value, "Oops"); // OK
static_assert(!B<int>::value, "Oops"); // Error

Again, the error occurs "within" the type indirect<int>,
because type int does not have a member type "type"
and this is not a "top-level" type error.

> > "
> > 7 The substitution occurs in all types and expressions that are used
> > in
> > the function type and in template parameter declarations.[..]
>
> > 8 [..] If a substitution results in an invalid type or expression,
> > type
> > deduction fails. An invalid type or expression is one that would be
> > ill-
> > formed if written using the substituted arguments. [..] Only invalid
> > types
> > and expressions in the immediate context of the function type and its
> > template parameter types can result in a deduction failure. [..]"
>
> I don't know how these passages reflect on the extended SFINAE rules. Is
> a substitution failure as allowed by extended SFINAE exactly the same as
> a type deduction failure as in 14.8.2 paragraph 8 ?

In fact the unofficial SFINAE term is ruled by a deduction failure.

> If that is the case I do not find among the possibiklities an attempt to
> instantiate a class template with the wrong number or wrong type of
> template parameters.

First, the above quoted general statement of 14.8.2/2 can be referred
to in C++03. As I said, this is not 100% clear because the following
individual list does not mention your example.

In C++0x there is no need anymore for an explicit listing. There is
a single-"catch all" phrase quoted above:

"If a substitution results in an invalid type or expression, type
deduction fails. An invalid type or expression is one that would
be ill-formed if written using the substituted arguments."

The further wording only restricts this to non-access situations

"Access checking is not done as part of the substitution process.
Consequently, when deduction succeeds, an access error could
still result when the function is instantiated."

and to types in the "immediate context":

"Only invalid types and expressions in the immediate context
of the function type and its template parameter types can result
in a deduction failure."

HTH & Greetings from Bremen,

Daniel Kr=FCgler


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Edward Diener <eldiener@tropicsoft.invalid>
Date: Tue, 20 Jul 2010 20:24:27 CST
Raw View
On 7/19/2010 7:21 PM, =?ISO-8859-1?Q?Daniel_Kr=FCgler?= wrote:
>
> On 19 Jul., 20:19, Edward Diener<eldie...@tropicsoft.invalid>  wrote:
>>
>> On 7/18/2010 5:27 PM, Daniel Kr=FCgler wrote:
>>
>>> I think this is clearly a compiler defect.
>>
>> Is it a compiler defect under the C++03 compiler using SFINAE, or are
>> you saying it is a compiler defect under the C++0x extended SFINAE ? If
>> it is a compiler defect only under the C++0x extended SFINAE then it is
>> quite possible that the three versions of compilers I have tested this
>> under do not yet implement the C++0x extended SFINAE.
>
> I ignored C++03 in my discussion because you already mentioned
> "extended SFINAE" rules, which are not available within C++03.
> Looking at the C++03 rules I would say that the wording is not
> really clear here. A weak interpretation of 14.8.2/2 would include
> your example, a strong interpretation would not.

Evidently the compilers I used, which were evidently using the C++03
SFINAE rules, flagged the code as a compiler error rather than a
SFINAE allowed substitution failure. The compilers I was using were
VC9, VC10, and the latest Comeau. I do know that VC9 and VC10 have no
claim to using the extended SFINAE rules, since neither mentions it in
their documentation about what's new in the compiler. As far as Comeau
it may be that I needed to turn on a compiler switch for extended
SFINAE. I will check that out. I also now have gcc4.5.0.1 so i will
look at that also.

> The part of the
> wording which can be interpreted to apply is bullet 2:
>
> =97 The specified template arguments must match the template
> parameters in kind (i.e., type, nontype, template), and there must
> not be more arguments than there are parameters; otherwise type
> deduction fails.
>
> The problem with the C++03 wording is that it describes are
> individual deduction failure cases in a long sub-bullet list below
> bullet 3. Your particular situation is not part of the list.
> The difference in C++0x is, that the individual list is gone and
> the rule is no simply that only types (and expressions) in the
> "immediate context" occurring in the function signature (return
> type, parameters) are considered. I described that in a lax
> way as "top-level types".

Unfortunately the individual list is still there in n3092 14.8.2 P8 in
a Note and the meaning of the Note is not very clear. One could assume
that the Note is listing all cases of type deduction failure to which
SFINAE applies or one could assume that the Note is simply giving just
some examples of cases of type deduction failure to which SFINAE
applies but the list is not all-inclusive. I realize this was taken
from the C++03 document, but I think the Note needs to be clarified.

>
>>> The new rules clearly say that a invalid type occurring on top
>>> level has to be silently ignored.
>>
>> The phrase "invalid type occurring on top level" appears to be yours,
>> and not in the working draft for the standard.
>
> Sure, it was just a non-normative description of the normative
> wording that I quoted later.
>
>>> This is essentially satisfied
>>> for your snippet. Situations which are *not* covered, are
>>> those where instantiation errors occur *within* the type - this
>>> doesn't happen here.
>>
>> I admit I was following the topic athttp://
>
> www.boostcon.com/community/wiki/show/ExtendedSFINAE/, and not
>>
>> attempting to understand what the working draft of the C++0x standard
>> says, where my search for SFINAE yielded nothing.
>
> Exactly, similar to my "top-level-type" wording, the term SFINAE does
> not officially exist in the standard, but it nonetheless became a
> non-normative technical term in C++ discussions (and your thread
> title contains this non-normative term as well).
>
>> It is explained at that web page that the one of the differences between
>> the previous way that SFINAE worked is that "the extended SFINAE rules
>> of C++0x generalize SFINAE to work with arbitrary expressions", where I
>> did not think that "typename U1::template M<U2, U3>*" was such an
>> expression; and where it says that:
>>
>> 'There are two classes of errors for which SFINAE still does not apply:
>>
>>     1. If the type-checking failure is due an access violation (e.g., x
>> + y resolves to a private operator+), that error is a "hard" error that
>> does not invoke SFINAE.
>
> Correct (and we don't have it in your example).
>
>>     2. If the type-checking failure occurs within the instantiation of a
>> class template or in the body of a function template, that error is a
>> "hard" error that does not invoke SFINAE.'
>
> Also correct. A simple example for such a "hard error" can be
> constructed, if we change my revised example as follows:
>
> struct A {
>  template<class T>
>  struct M {
>    M(int, T = T()){}
>  };
> };
>
> template<class T1, class T2 = void>
> struct B {
>  template<class U1, class U2>
>  static char test(typename U1::template M<U2>);
>
>  template<class, class>
>  static char (&test(...))[2];
>
>  static const bool value = sizeof(test<T1, T2>(0)) == 1;
>
> };
>
> B<A>  b;
>
> static_assert(!B<A>::value, "Ouch");
>
> This time we might also expect that this should also be well-
> formed, relying on the assumption that a function parameter
> of type void cannot be valid. But this is a error that happens
> "within" A::M<void>  and not at the immediate type occurring
> in the function declaration
>
>  template<class U1, class U2>
>  char test(typename U1::template M<U2>);
>
>> In this case I did not know if the second exception applied because the
>> phrase "within the instantiation of a class template" could or could not
>> apply to the top level matching of template parameters. If I have:
>>
>> template<class X>  struct Y { };
>>
>> and the instantiation of the template with:
>>
>> Y<someType,someOtherType>  z;
>>
>> one could or could not interpret the "within instantiation of the class
>> template" as including the matching of template parameters.
>>>
>>> FCD 14.8.2/7+8:
>
> The point is that the involved type shows up directly in the
> function declaration. My loose "top-level" term was supposed to
> refer to this immediately occurring type.

I understand what you are saying now. I don't think n3092 makes that
completely clear.

> Another good non-SFINAE
> example is this one:
>
> template<typename T>
> struct indirect {
>  typedef typename T::type type;
> };
>
> template<class T>
> struct B {
>  template<class U>
>  static char test(typename indirect<T>::type);
>
>  template<class>
>  static char (&test(...))[2];
>
>  static const bool value = sizeof(test<T>(0)) == 1;
> };
>
> struct S {
>  typedef int type;
> };
>
> static_assert(B<S>::value, "Oops"); // OK
> static_assert(!B<int>::value, "Oops"); // Error
>
> Again, the error occurs "within" the type indirect<int>,
> because type int does not have a member type "type"
> and this is not a "top-level" type error.

Your examples show what you mean quite well.

>
>>> "
>>> 7 The substitution occurs in all types and expressions that are used
>>> in
>>> the function type and in template parameter declarations.[..]
>>
>>> 8 [..] If a substitution results in an invalid type or expression,
>>> type
>>> deduction fails. An invalid type or expression is one that would be
>>> ill-
>>> formed if written using the substituted arguments. [..] Only invalid
>>> types
>>> and expressions in the immediate context of the function type and its
>>> template parameter types can result in a deduction failure. [..]"
>>
>> I don't know how these passages reflect on the extended SFINAE rules. Is
>> a substitution failure as allowed by extended SFINAE exactly the same as
>> a type deduction failure as in 14.8.2 paragraph 8 ?
>
> In fact the unofficial SFINAE term is ruled by a deduction failure.

I was going by SFINAE: Substitution Failure Is Not An Error. That is
why I asked whether the term 'type deduction failure' in 14.8.2 P8 is
equivalent to 'substitution failure' in SFINAE.

>
>> If that is the case I do not find among the possibiklities an attempt to
>> instantiate a class template with the wrong number or wrong type of
>> template parameters.
>
> First, the above quoted general statement of 14.8.2/2 can be referred
> to in C++03. As I said, this is not 100% clear because the following
> individual list does not mention your example.

That was my point.

>
> In C++0x there is no need anymore for an explicit listing. There is
> a single-"catch all" phrase quoted above:
>
> "If a substitution results in an invalid type or expression, type
> deduction fails. An invalid type or expression is one that would
> be ill-formed if written using the substituted arguments."

The catch-all phrase is still pretty general.

>
> The further wording only restricts this to non-access situations
>
> "Access checking is not done as part of the substitution process.
> Consequently, when deduction succeeds, an access error could
> still result when the function is instantiated."
>
> and to types in the "immediate context":
>
> "Only invalid types and expressions in the immediate context
> of the function type and its template parameter types can result
> in a deduction failure."

This is better but I would still argue that the term "immediate
context" needs to be elucidated. I know what you say it means, by your
examples, and I can agree with you since your examples make it clear
what "immediate context" is there. Perhaps I am being unfair in
assuming that "immediate context" is not readily understood, but I
certainly did not understand to what exactly it referred without your
explaining it.

I have a feeling that compiler vendors who do implement the C++0x
extended SFINAE rules may find the wording not specific enough to
their liking also, but maybe I will be proved wrong.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Tue, 20 Jul 2010 20:23:42 CST
Raw View
On 20 Jul., 01:21, =?ISO-8859-1?Q?Daniel_Kr=FCgler?=
<daniel.krueg...@googlemail.c=.om> wrote:
> On 19 Jul., 20:19, Edward Diener <eldie...@tropicsoft.invalid> wrote:
>
> > On 7/18/2010 5:27 PM, Daniel Kr=FCgler wrote:
>
> > > I think this is clearly a compiler defect.
>
> > Is it a compiler defect under the C++03 compiler using SFINAE, or are
> > you saying it is a compiler defect under the C++0x extended SFINAE ? If
> > it is a compiler defect only under the C++0x extended SFINAE then it is
> > quite possible that the three versions of compilers I have tested this
> > under do not yet implement the C++0x extended SFINAE.
>
> I ignored C++03 in my discussion because you already mentioned
> "extended SFINAE" rules, which are not available within C++03.
> Looking at the C++03 rules I would say that the wording is not
> really clear here. A weak interpretation of 14.8.2/2 would include
> your example, a strong interpretation would not. The part of the
> wording which can be interpreted to apply is bullet 2:
>
> =97 The specified template arguments must match the template
> parameters in kind (i.e., type, nontype, template), and there must
> not be more arguments than there are parameters; otherwise type
> deduction fails.

Sorry, this was a wrong reference: Above normative wording
describes the kind and number of the *function* template, not
of templates that might occur as function parameters or
return type. Apart from this part, the remaining argumentation
should still be correct.

Sorry for any confusion & Greetings from Bremen,

Daniel Kr   gler



--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =3D?ISO-8859-1?Q?Daniel_Kr=3DFCgler?=3D <daniel.kruegler@googlemail.c=.om>
Date: Wed, 21 Jul 2010 11:40:54 CST
Raw View
On Jul 21, 4:24 am, Edward Diener <eldie...@tropicsoft.invalid> wrote:
> On 7/19/2010 7:21 PM, =?ISO-8859-1?Q?Daniel_Kr=FCgler?= wrote:

[..]

> Unfortunately the individual list is still there in n3092 14.8.2 P8 in
> a Note and the meaning of the Note is not very clear. One could assume
> that the Note is listing all cases of type deduction failure to which
> SFINAE applies or one could assume that the Note is simply giving just
> some examples of cases of type deduction failure to which SFINAE
> applies but the list is not all-inclusive. I realize this was taken
> from the C++03 document, but I think the Note needs to be clarified.

I disagree: The reason for a note is to exemplify the normative
wording and to make things clearer that might not be obvious
from the normative wording. I don't see how the example could
in anyway influence the interpretation of the normative wording
unless you find an example that would *contradict* the normative
wording. In this case the normative wordings "wins" in an
lawyer's contest, but it is probably a good reason to open
an issue to see whether the example was broken or whether
the intention of the normative wording was to make the example
well-formed. In the latter case the normative wording will probably
be fixed. I have not found any example in the FCD list that
would break with the normative wording. Please send an issue
on this list, if you believe the contrary.

> > The point is that the involved type shows up directly in the
> > function declaration. My loose "top-level" term was supposed to
> > refer to this immediately occurring type.
>
> I understand what you are saying now. I don't think n3092 makes that
> completely clear.

[..]

> This is better but I would still argue that the term "immediate
> context" needs to be elucidated. I know what you say it means, by your
> examples, and I can agree with you since your examples make it clear
> what "immediate context" is there. Perhaps I am being unfair in
> assuming that "immediate context" is not readily understood, but I
> certainly did not understand to what exactly it referred without your
> explaining it.
>
> I have a feeling that compiler vendors who do implement the C++0x
> extended SFINAE rules may find the wording not specific enough to
> their liking also, but maybe I will be proved wrong.

Normative wording of an international standard does not
have the same demand to be as unmistakable as the
instruction sheet for a microwave in some countries is
supposed to be. It does not need to make clear that you
should not put any pets into such a device, for example ;-)

It is written for technical experts to be able to produce a
compiler that satisfies these requirements - it is not
supposed to be a replacement of some compiler or library
vendor's product description.

I don't deny that there always will be some risk that
someone get's the intention wrong. It might simply be
an obvious interpretation error of this person, but it
might be a defect in the standard. If such things happen,
an issue will be raised at some point in time.

> > In fact the unofficial SFINAE term is ruled by a deduction failure.
>
> I was going by SFINAE: Substitution Failure Is Not An Error. That is
> why I asked whether the term 'type deduction failure' in 14.8.2 P8 is
> equivalent to 'substitution failure' in SFINAE.

The standard does not answer this question, so you cannot
find the answer for this in the standard. Personally I would
say: Yes, 14.8.2/8 is the central place of the standard that
"controls" SFINAE. We might need to extend to further
parts of the standard, if we want to discuss the effects of
several overloads of a function template that take advantage
of type deduction failures, but at the level of this discussion,
it should be sufficient.

HTH & Greetings from Bremen,

Daniel Kr=FCgler


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Edward Diener <eldiener@tropicsoft.invalid>
Date: Sat, 17 Jul 2010 07:00:27 CST
Raw View
The code is:

----------------------------------------------------------------------

struct test_default { };

struct AType
 {
 template <class X> struct AMemberTemplate { };
 };

template
 <
 class T,
 class P1 = test_default,
 class P2 = test_default
>
struct test_template
{

 private:

 template
   <
   class T1,
   class P1_1,
   class P1_2
   >
 static char test(typename T1::template AMemberTemplate<P1_1,P1_2> *);

 template
   <
   class T1,
   class P1_1,
   class P1_2
   >
 static char (&test(...))[2];

 public:

 typedef test_template type;

 static const bool value = (sizeof(test<T,P1,P2>(0))==1);
};

template
 <
 class T,
 class P1
>
struct test_template
 <
 T,
 P1,
 test_default
>
{

 private:

 template
   <
   class T1,
   class P1_1
   >
 static char test(typename T1::template AMemberTemplate<P1_1> *);

 template
   <
   class T1,
   class P1_1
   >
 static char (&test(...))[2];

 public:

 typedef test_template type;

 static const bool value = (sizeof(test<T,P1>(0))==1);
};

template
 <
 class T
>
struct test_template
 <
 T,
 test_default,
 test_default
>
{
 typedef test_template type;

 static const bool value = false;
};

test_template<AType,int,int> tt;


----------------------------------------------------------------------

The last line fails with a compiler error because SFINAE substitution
does not apply when a template match is found but the parameter
substitution is in error.

Yet if I comment out the template definition in AType completely, so
that it reads:

struct AType
 {
//  template <class X> struct AMemberTemplate { };
 };

there is no compiler error because now SFINAE does apply.

I find this a strange anomaly. Essentially the valid subsitution
failures for SFINAE include not finding a nested class member but does
not include finding a nested class template instantiated with the
wrong number or wrong type of parameters.

My reading of the upcoming extended SFINAE is that the situation has
not changed in this particular respect. If that is so was there any
consideration given that it should change and that extended SFINAE
should also consider incorrect class template parameter substitution
as a valid substitution failure ?

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Sun, 18 Jul 2010 15:27:25 CST
Raw View
On 17 Jul., 15:00, Edward Diener <eldie...@tropicsoft.invalid> wrote:
> The code is:

[..]

I took the liberty to simplify your program, because
large parts of it unnecessarily complicate what you
want to show. E.g we can ignore all your partial
specializations. I end up in the following minimum
code:

struct A { template <class> struct M { }; };

template<class T1, class T2 = void, class T3 = void>
struct B {
 template<class U1, class U2, class U3>
 static char test(typename U1::template M<U2, U3>*);

 template<class, class, class>
 static char (&test(...))[2];

 static const bool value = sizeof(test<T1, T2, T3>(0)) == 1;
};

B<A> b;

static_assert(!B<A>::value, "Ouch");

[If you think that this incorrectly models your example,
don't shy away from complaining ;-)]

> The last line fails with a compiler error because SFINAE substitution
> does not apply when a template match is found but the parameter
> substitution is in error.

I think this is clearly a compiler defect.

> Yet if I comment out the template definition in AType completely, so
> that it reads:
>
> struct AType
>  {
> //  template <class X> struct AMemberTemplate { };
>  };
>
> there is no compiler error because now SFINAE does apply.
>
> I find this a strange anomaly. Essentially the valid subsitution
> failures for SFINAE include not finding a nested class member but does
> not include finding a nested class template instantiated with the
> wrong number or wrong type of parameters.
>
> My reading of the upcoming extended SFINAE is that the situation has
> not changed in this particular respect. If that is so was there any
> consideration given that it should change and that extended SFINAE
> should also consider incorrect class template parameter substitution
> as a valid substitution failure ?

The new rules clearly say that a invalid type occurring on top
level has to be silently ignored. This is essentially satisfied
for your snippet. Situations which are *not* covered, are
those where instantiation errors occur *within* the type - this
doesn't happen here.

FCD 14.8.2/7+8:

"
7 The substitution occurs in all types and expressions that are used
in
the function type and in template parameter declarations.[..]

8 [..] If a substitution results in an invalid type or expression,
type
deduction fails. An invalid type or expression is one that would be
ill-
formed if written using the substituted arguments. [..] Only invalid
types
and expressions in the immediate context of the function type and its
template parameter types can result in a deduction failure. [..]"

I don't understand what you read in the most recent draft that
would exclude your example from this.

HTH & Greetings from Bremen,

Daniel Kr   gler


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Edward Diener <eldiener@tropicsoft.invalid>
Date: Mon, 19 Jul 2010 12:19:31 CST
Raw View
On 7/18/2010 5:27 PM, Daniel Kr   gler wrote:
> On 17 Jul., 15:00, Edward Diener<eldie...@tropicsoft.invalid>  wrote:
>> The code is:
>
> [..]
>
> I took the liberty to simplify your program, because
> large parts of it unnecessarily complicate what you
> want to show. E.g we can ignore all your partial
> specializations. I end up in the following minimum
> code:
>
> struct A { template<class>  struct M { }; };
>
> template<class T1, class T2 = void, class T3 = void>
> struct B {
>   template<class U1, class U2, class U3>
>   static char test(typename U1::template M<U2, U3>*);
>
>   template<class, class, class>
>   static char (&test(...))[2];
>
>   static const bool value = sizeof(test<T1, T2, T3>(0)) == 1;
> };
>
> B<A>  b;
>
> static_assert(!B<A>::value, "Ouch");
>
> [If you think that this incorrectly models your example,
> don't shy away from complaining ;-)]

It models my example correctly.

>
>> The last line fails with a compiler error because SFINAE substitution
>> does not apply when a template match is found but the parameter
>> substitution is in error.
>
> I think this is clearly a compiler defect.

Is it a compiler defect under the C++03 compiler using SFINAE, or are
you saying it is a compiler defect under the C++0x extended SFINAE ? If
it is a compiler defect only under the C++0x extended SFINAE then it is
quite possible that the three versions of compilers I have tested this
under do not yet implement the C++0x extended SFINAE.

>
>> Yet if I comment out the template definition in AType completely, so
>> that it reads:
>>
>> struct AType
>>   {
>> //  template<class X>  struct AMemberTemplate { };
>>   };
>>
>> there is no compiler error because now SFINAE does apply.
>>
>> I find this a strange anomaly. Essentially the valid subsitution
>> failures for SFINAE include not finding a nested class member but does
>> not include finding a nested class template instantiated with the
>> wrong number or wrong type of parameters.
>>
>> My reading of the upcoming extended SFINAE is that the situation has
>> not changed in this particular respect. If that is so was there any
>> consideration given that it should change and that extended SFINAE
>> should also consider incorrect class template parameter substitution
>> as a valid substitution failure ?
>
> The new rules clearly say that a invalid type occurring on top
> level has to be silently ignored.

The phrase "invalid type occurring on top level" appears to be yours,
and not in the working draft for the standard.

> This is essentially satisfied
> for your snippet. Situations which are *not* covered, are
> those where instantiation errors occur *within* the type - this
> doesn't happen here.

I admit I was following the topic at
http://www.boostcon.com/community/wiki/show/ExtendedSFINAE/, and not
attempting to understand what the working draft of the C++0x standard
says, where my search for SFINAE yielded nothing.

It is explained at that web page that the one of the differences between
the previous way that SFINAE worked is that "the extended SFINAE rules
of C++0x generalize SFINAE to work with arbitrary expressions", where I
did not think that "typename U1::template M<U2, U3>*" was such an
expression; and where it says that:

'There are two classes of errors for which SFINAE still does not apply:

    1. If the type-checking failure is due an access violation (e.g., x
+ y resolves to a private operator+), that error is a "hard" error that
does not invoke SFINAE.
    2. If the type-checking failure occurs within the instantiation of a
class template or in the body of a function template, that error is a
"hard" error that does not invoke SFINAE.'

In this case I did not know if the second exception applied because the
phrase "within the instantiation of a class template" could or could not
apply to the top level matching of template parameters. If I have:

template <class X> struct Y { };

and the instantiation of the template with:

Y<someType,someOtherType> z;

one could or could not interpret the "within instantiation of the class
template" as including the matching of template parameters.

>
> FCD 14.8.2/7+8:
>
> "
> 7 The substitution occurs in all types and expressions that are used
> in
> the function type and in template parameter declarations.[..]
>
> 8 [..] If a substitution results in an invalid type or expression,
> type
> deduction fails. An invalid type or expression is one that would be
> ill-
> formed if written using the substituted arguments. [..] Only invalid
> types
> and expressions in the immediate context of the function type and its
> template parameter types can result in a deduction failure. [..]"

I don't know how these passages reflect on the extended SFINAE rules. Is
a substitution failure as allowed by extended SFINAE exactly the same as
a type deduction failure as in 14.8.2 paragraph 8 ? If that is the case
I do not find among the possibiklities an attempt to instantiate a class
template with the wrong number or wrong type of template parameters.


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]