SFINAE revisited

F

Fraser Ross

Is a local class in any way less hidden with the changes? I have seen
one described as final because outside code cannot derive from one. Is
this still the case? I would think not.

Fraser.
 
J

Joe Greer

"Joe Greer"

Its explicitly instantiated as so:
P< B >

Well, from my point of view (which admittedly is probably wrong because
it is so simple and understandable) once you have explicitly
instantiated a template with something like P<B> it should be as if the
class were really as if you had written:

class P
{
public:
P(B *) {}
//etc
}

And type deductions would be based off of type B. That is, the actual
type passed into the constructor no longer matters because you
explicitly told it the base class.
The type of "new D" is unimportant in deciding the type of T. Are you
aware that there isn't implicit conversions involved in template
argument deduction? U can't be B.

I don't think I even implied that the conversion had anything to do with
argument deduction.


joe
 
J

James Kanze

Is a local class in any way less hidden with the changes? I
have seen one described as final because outside code cannot
derive from one. Is this still the case? I would think not.

It never was the case, as far as I know.

I don't think that local classes, per se, will change much.
What is being changed is that at least in some cases, you will
be allowed to instantiate a template with a name which doesn't
have external linkage.
 
J

James Kanze

@news.astraweb.com:
Well, from my point of view (which admittedly is probably
wrong because it is so simple and understandable) once you
have explicitly instantiated a template with something like
P<B> it should be as if the class were really as if you had
written:
class P
{
public:
P(B *) {}
//etc
}
And type deductions would be based off of type B. That is,
the actual type passed into the constructor no longer matters
because you explicitly told it the base class.

There were two constructors, one of which was a member template.
So the compiler has to do overload resolution to choose the
constructor, and template argument deduction on the member
template to know which one it includes in the overload set.
 
C

courpron

Gennaro said:
Right now I can't check the standard with the care it deserves, but
I believe it boils down to this: substitution (deduction) *succeeds*,
because "usage of local class for template type argument" isn't listed
as a case of substitution failure; so, a point of instantiation is
created for both constructors, and that leads to an error for each
constructor. This is before there's any chance to add the instantiations
to the overload set, and thus there's really no overload resolution. But
all this should be backed up with a few paragraph numbers from the
standard :) I'll try doing that tomorrow.

Sorry, of course that's *one* error, not an error for each
constructor; I should refrain from posting at the end of a day like
yesterday was. Apart from that oversight, I think the analysis is
correct.

The text of core issue 488, which I linked to in the other post,
already mentions the relevant sections of the standard, particularly
14.8.2 [temp.deduct] par. 2 and the fact that substituting a local
type isn't listed there as a SFINAE case. (In and of itself that
section concerns the case of explicitly specified template arguments,
but then the deduced case is re-conducted back to the former).

There is no reconduction. 14.8.2/2 concerns explicit template
arguments only.
Contrary to what the core issue 488 says, the relevant section is
14.8.2.4.

Alexandre Courpron.
 
G

Gennaro Prota

The text of core issue 488, which I linked to in the other post,
already mentions the relevant sections of the standard, particularly
14.8.2 [temp.deduct] par. 2 and the fact that substituting a local
type isn't listed there as a SFINAE case. (In and of itself that
section concerns the case of explicitly specified template arguments,
but then the deduced case is re-conducted back to the former).

There is no reconduction. 14.8.2/2 concerns explicit template
arguments only.
Contrary to what the core issue 488 says, the relevant section is
14.8.2.4.

Did you mean 14.8.2/4?
 
C

courpron

(e-mail address removed) wrote:

     [...]
The text of core issue 488, which I linked to in the other post,
already mentions the relevant sections of the standard, particularly
14.8.2 [temp.deduct] par. 2 and the fact that substituting a local
type isn't listed there as a SFINAE case. (In and of itself that
section concerns the case of explicitly specified template arguments,
but then the deduced case is re-conducted back to the former).
There is no reconduction. 14.8.2/2 concerns explicit template
arguments only.
Contrary to what the core issue 488 says, the relevant section is
14.8.2.4.

Did you mean 14.8.2/4?

No, I mean 14.8.2.4 [temp.deduct.type] (the whole section).

Alexandre Courpron.
 
G

Gennaro Prota

Did you mean 14.8.2/4?

No, I mean 14.8.2.4 [temp.deduct.type] (the whole section).

Hmm, yes, I think you are right. It's odd that the text of the core
issue gets it wrong, though, even in the proposed resolution from
October 2005!

Thanks for making me notice this.
 
C

courpron

No, I mean 14.8.2.4 [temp.deduct.type] (the whole section).

Hmm, yes, I think you are right. It's odd that the text of the core
issue gets it wrong, though, even in the proposed resolution from
October 2005!

Thanks for making me notice this.

You're welcome.

I guess that core issues reports can also have issues.

In the C++ standard, the whole section about templates and argument
deduction uses maybe confusing terminology.
For instance, consider the following example :

****
template < class T >
void f( T ) {}

....

f(0); // #1
f<int>(0); // #2
****

Usually, one could say that there is a template argument deduction in
the first call and not the second one. This is the natural and popular
meaning of "argument deduction", used in many technical papers, books,
faqs, etc...

However, there is actually a template argument deduction for both
calls. For the second call, argument deduction just does nothing and
*succeeds*. If the explicit template arguments had led to an invalid
type as described in 14.8.2/2, then the deduction would have just
*failed*. That's why SFINAE can occur when there is only an explicit
specification of template arguments ( since SFINAE comes when argument
deduction fails ). I insist on the fact that argument deduction exists
in the second call, but does nothing : that means that there is no
*deduced* template argument from that call, while there is one deduced
template argument from the first call. That's why the core issue #250
was arised for example :
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#250


The standard says that (14.8.2/2) :
"When an explicit template argument list is specified, the template
arguments must be compatible with the template parameter list and must
result in a valid function type as described below; otherwise type
deduction fails."

That seems contradictory only if you use the popular (and inaccurate)
meaning of "deduction". The core issue 488 took that sentence without
the first part ("When an explicit template argument list is
specified"). That omission led to a wrong assumption.


Alexandre Courpron.
 
C

courpron

****
template < class T >
void f( T ) {}

f(0); //  #1
f<int>(0); // #2
****
Usually, one could say that there is a template argument deduction in
the first call and not the second one. This is the natural and popular
meaning of "argument deduction", used in many technical papers, books,
faqs, etc...
However, there is actually a template argument deduction for both
calls. For the second call, argument deduction just does nothing and
*succeeds*. If the explicit template arguments had led to an invalid
type as described in 14.8.2/2, then the deduction would have just
*failed*. That's why SFINAE can occur when there is only an explicit
specification of template arguments ( since SFINAE comes when argument
deduction fails ).

Wait a minute!  This just does not sound right.  Consider this

     template<class T> void foo(T, char T::* = 0);
     void foo(int);
     ...
     foo(0);

What would happen?  Deducing T (for the first 'foo') as 'int' (which is
what I'd expect) means that the second argument is invalid since 'int
does not have members.  Isn't this a case of SFINAE?  (that's a
rhetorical question).  Well, there is no explicit specification of the
template arguments for 'foo' in the expression that requires type
deduction, is there?

Looking forward to your comments.

Yes, there is SFINAE here and that doesn't invalidate what I said.

I said that SFINAE *can* occur when there is only an explicit
specification of template arguments. That doesn't mean it can't occur
when there is no explicit template arguments. Note that I used the
word "only" here to say that there is "only" explicit template
arguments (without any deduced argument). I didn't mean that "SFINAE
can *only* occur when there is only an explicit specification of
template arguments".

Now why am I talking about explicit template arguments specifically ?
Because SFINAE comes when *argument deduction fails*. The important
terms here are "argument deduction". From that definition, it is
obvious that SFINAE can be applied when deduced template arguments are
involved. But SFINAE can also apply when there are only explicit
template arguments (and no deduced argument at all) and that is not
obvious because, from a popular conception, there is no argument
deduction with explicit template arguments only (which is wrong).

Alexandre Courpron.
 
G

Gennaro Prota

Gennaro said:
There is no reconduction. 14.8.2/2 concerns explicit template
arguments only.
Contrary to what the core issue 488 says, the relevant section is
14.8.2.4.
Did you mean 14.8.2/4?

No, I mean 14.8.2.4 [temp.deduct.type] (the whole section).

Hmm, yes, I think you are right. It's odd that the text of the core
issue gets it wrong, though, even in the proposed resolution from
October 2005!

Thanks for making me notice this.

As I said, Alexandre's reading of the standard seemed pretty correct
to me. So, I wrote to William M. Miller to point out that, apparently,
the text of core issue 488 was referencing the wrong section of the
standard. Here is a summary of the resulting conversation; the text is
slightly edited and reordered to make it (hopefully) clearer in the
context of this thread, and is being forwarded to the newsgroup with
his permission.

WM:
The reference to 14.8.2 in issue 488 is there because the list of
things that cause deduction failures is in 14.8.2 (or, rather, it was;
the version of the Standard incorporating paper N2657 no longer has a
normative list of deduction failures). There was no implication that
14.8.2 was the place that described how template argument deduction
was done for this particular example.

Me:
The problem is, IIUC, that there's no such a thing as "*the* list of
things that cause deduction failures"; but there is "the list of
things that cause deduction failures *when there's an explicit
template argument list*".

WM:
The presentation in 14.8.2 and subsections has always been somewhat
problematic. It's complicated trying to relate all the contexts in
which template argument deduction is done and all the ways a given
template argument value is obtained (explicitly specified, deduced, or
via a default argument), and the fact that the specification evolved,
rather than being written all at once, also contributed to the general
lack of clarity.

However, the intent behind the statement "Type deduction may fail for
the following reasons" was that the following list of bullets applied
regardless of whether the template arguments were deduced, explicitly
specified, or from a default template argument. (That also applies to
the second bullet in that list [not sub-bullet], requiring that a
non-type template argument be convertible to the type of the
corresponding parameter.) The idea was that you first substitute any
explicit template arguments, then attempt to deduce the remaining
arguments as specified in the subsections of 14.8.2, then use default
arguments for any parameters that do not have arguments at that point.
If, after substituting all the arguments for uses of parameters in the
declaration, you end up with a type that is invalid for any of the
reasons in 14.8.2p2, deduction fails for that particular
specialization.

You can see that intention reflected, although imperfectly, in the
wording of 14.8.2p5 (in the current WP; it was similar in the
Standard, but missing the mention of default arguments):

When all template arguments have been deduced or obtained
from default template arguments, all uses of template
parameters in non-deduced contexts are replaced with the
corresponding deduced or default argument values. If the
substitution results in an invalid type, as described above,
type deduction fails.

Note the explicit linking of deduced and default arguments, not just
explicitly-specified arguments, with the reference to p2 ("as
described above").

I think the revision in the current WP makes this clearer, although
I'm sure that further improvement is possible.

Me:
Ah, thanks! [...] I had noticed the wording in 14.8.2p5; in fact
here's what I wrote on c.l.c++.m:

The text of core issue 488, which I linked to in the other
post, already mentions the relevant sections of the standard,
particularly 14.8.2 [temp.deduct] par. 2 [snip...] (In and of
itself that section concerns the case of explicitly specified
template arguments, but then the deduced case is re-conducted
back to the former).

When I say "re-conducted back" I'm thinking exactly of the "as
described above" which you cite. But A. Courpron replied to that with

There is no reconduction. 14.8.2/2 concerns explicit template
arguments only. Contrary to what the core issue 488 says, the
relevant section is 14.8.2.4.

and, upon strict reading, he seemed to be correct.

WM:
I hadn't thought about it from that perspective, but it's easy to see
how one would reach that conclusion from the existing wording. That
does appear to be what it's saying, but that was not the intent.
Hopefully things will be better with the current revision.
 
M

Michael DOUBEZ

Gennaro Prota a écrit :
Gennaro said:
There is no reconduction. 14.8.2/2 concerns explicit template
arguments only.
Contrary to what the core issue 488 says, the relevant section is
14.8.2.4.
Did you mean 14.8.2/4?

No, I mean 14.8.2.4 [temp.deduct.type] (the whole section).

Hmm, yes, I think you are right. It's odd that the text of the core
issue gets it wrong, though, even in the proposed resolution from
October 2005!

Thanks for making me notice this.

[lot of standardisation related stuff]

comp.std.c++ has really been down for too long. :)
 
C

courpron

Gennaro Prota wrote:
[...]

As I said, Alexandre's reading of the standard seemed pretty correct
to me. So, I wrote to William M. Miller to point out that, apparently,
the text of core issue 488 was referencing the wrong section of the
standard. Here is a summary of the resulting conversation; the text is
slightly edited and reordered to make it (hopefully) clearer in the
context of this thread, and is being forwarded to the newsgroup with
his permission.

WM:
The reference to 14.8.2 in issue 488 is there because the list of
things that cause deduction failures is in 14.8.2 (or, rather, it was;
the version of the Standard incorporating paper N2657 no longer has a
normative list of deduction failures).  There was no implication that
14.8.2 was the place that described how template argument deduction
was done for this particular example.

Me:
The problem is, IIUC, that there's no such a thing as "*the* list of
things that cause deduction failures"; but there is "the list of
things that cause deduction failures *when there's an explicit
template argument list*".

WM:
The presentation in 14.8.2 and subsections has always been somewhat
problematic.  It's complicated trying to relate all the contexts in
which template argument deduction is done and all the ways a given
template argument value is obtained (explicitly specified, deduced, or
via a default argument), and the fact that the specification evolved,
rather than being written all at once, also contributed to the general
lack of clarity.

However, the intent behind the statement "Type deduction may fail for
the following reasons" was that the following list of bullets applied
regardless of whether the template arguments were deduced, explicitly
specified, or from a default template argument.  (That also applies to
the second bullet in that list [not sub-bullet], requiring that a
non-type template argument be convertible to the type of the
corresponding parameter.)  The idea was that you first substitute any
explicit template arguments, then attempt to deduce the remaining
arguments as specified in the subsections of 14.8.2, then use default
arguments for any parameters that do not have arguments at that point.
If, after substituting all the arguments for uses of parameters in the
declaration, you end up with a type that is invalid for any of the
reasons in 14.8.2p2, deduction fails for that particular
specialization.

You can see that intention reflected, although imperfectly, in the
wording of 14.8.2p5 (in the current WP; it was similar in the
Standard, but missing the mention of default arguments):

   When all template arguments have been deduced or obtained
   from default template arguments, all uses of template
   parameters in non-deduced contexts are replaced with the
   corresponding deduced or default argument values.  If the
   substitution results in an invalid type, as described above,
   type deduction fails.

Note the explicit linking of deduced and default arguments, not just
explicitly-specified arguments, with the reference to p2 ("as
described above").

I think the revision in the current WP makes this clearer, although
I'm sure that further improvement is possible.

Me:
Ah, thanks! [...] I had noticed the wording in 14.8.2p5; in fact
here's what I wrote on c.l.c++.m:

  The text of core issue 488, which I linked to in the other
  post, already mentions the relevant sections of the standard,
  particularly 14.8.2 [temp.deduct] par. 2 [snip...] (In and of
  itself that section concerns the case of explicitly specified
  template arguments, but then the deduced case is re-conducted
  back to the former).

When I say "re-conducted back" I'm thinking exactly of the "as
described above" which you cite. But A. Courpron replied to that with

  There is no reconduction. 14.8.2/2 concerns explicit template
  arguments only. Contrary to what the core issue 488 says, the
  relevant section is 14.8.2.4.

and, upon strict reading, he seemed to be correct.

WM:
I hadn't thought about it from that perspective, but it's easy to see
how one would reach that conclusion from the existing wording.  That
does appear to be what it's saying, but that was not the intent.
Hopefully things will be better with the current revision.

Very interesting.

However, consider the following 2 points :

1) About 14.8.2/5 (~ 14.8.2/4 in the current standard) :
This paragraph concerns the substitution of deduced template arguments
in nondeduced contexts only.

Example :
****
template < class T >
struct foo { typedef T type; };

template < class T >
void f( T arg1, typename foo<T>::type arg2) {}
...

f(0,0);
****

Here the function specialization is done in 2 steps :
- template argument deduction, done for arg1 only
- substitution of T for arg2

Between these 2 steps, T is known. But, for step 2, it doesn't matter
where T comes from, it can be a deduced argument or an explicit
argument, it should not matter. That's why it's perfectly logical that
"substitution of deduced template arguments in nondeduced contexts"
follows the same rules as "substitution of explicit template
arguments". There is no reconduction of the whole process of template
argument deduction here.


2) Explicit template arguments can't have the same list of type
deduction failures than deduced template arguments, because failures
in one context are meaningless in the another. Here is one example of
type deduction failure for explicit arguments :

Attempting to use a type that is not a class type in a qualified name.
[Example:
template <class T> int f(typename T::B*);
int i = f<int>(0);
]

You can see that template argument deduction can't lead to such case,
except for the "substitution of deduced template arguments in
nondeduced contexts" described in 14.8.2/4. All of this is currently
very logical to me.

The core issue 488 clearly doesn't fall in the list of type deduction
failures for explicit template arguments.

Alexandre Courpron.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top