Doc. No.: WG21/N1490, J16/03-0073
Date: 2003-09-08
Reply to: Clark Nelson
Phone: +1-503-712-8433
Email: clark.nelson@intel.com

Proposed resolution of core issue 301

Introduction

It turns out that issue 301 is a duplicate of issue 38, which was resolved in the TC. I am reassured by the fact that I independently came up with the same grammar change that Jamie Schmeiser did. For reference, here is that grammar change (from 13.5):

operator-function-id:
operator operator
operator operator < template-argument-listopt >

However, when I looked at the matter carefully, I discovered that there are many changes that need to be made to resolve the issue, which were not made as part of issue 38. Moreover, for the sake of those changes, and to have a convenient term for an important concept, the grammar needs to be tweaked a bit.

In several places, there are restrictions or conditions on "being a template-id". Of course an operator-function-id with a template-argument-list isn't a template-id, but where those restrictions and conditions apply to function templates, it shouldn't matter whether the function has a name or an operator-function-id. My first thought was to refer instead to the presence of a template-argument-list, but of course that's optional. The restrictions and conditions are really syntactic, and actually refer to the presence of the angle brackets delimiting the template-argument-list, if present. So I propose to add a new production to refer to the delimited (optional) template-argument-list:

operator-function-id:
operator operator
operator operator template-argument-clause
template-id:
template-name template-argument-clause
template-argument-clause:
< template-argument-listopt >

The other necessary changes have to do with some consequences of the grammar changes:

Operator function template description

The smallest possible addition would be in 13.51:

A function declaration having one of the following operator-function-ids as its name declares an operator function. A function template declaration having one of the following operator-function-ids as its name declares an operator function template. A specialization of an operator function template is also an operator function. An operator function is said to implement the operator named in its operator-function-id.

If any other change were necessary, then it would certainly be necessary to modify 13.56, which describes operator functions. However, it is at least conceivable that the above change would imply everything else that is true of operator function templates. But even if so, it may be desirable to be a little more explicit.

The shift-reduce conflict

For template names, this is currently addressed in the first sentence of 14.23:

After name lookup (3.4) finds that a name is a template-name, if this name is followed by a <, the < is always taken as the beginning of a template-argument-list and never as a name followed by the less-than operator.

This description seems to be adequate for names of class templates. As far as I can tell, the only ambiguity it resolves is from something that starts with new X <, in the scope of a class template X. But even without the grammar change, it was inadequate for names of function templates.

Probably after an identifier I, < should always be interpreted as introducing a template-argument-clause if any member of the overload set identified by I is a function template. After all, function pointers are very rarely compared for ordering, and it's not clear what other rule might be workable.

My proposed revision of 14.23:

After name lookup (3.4) finds that a name is a template-name, or refers to a set of overloaded functions any member of which is a function template, if this name is followed by a <, the < is always taken as the beginning of a template-argument-clause and never as a name followed by the less-than operator.

Clearly, this change is technically unrelated to operator functions. But it still seems to be necessary.

Getting back to operator function templates, I propose to add the following to 13.51, between the grammar rules and the note:

If any member of the set of overloaded operator functions implementing the operator is a template, any immediately following < is interpreted as introducing a template-argument-clause, and not as a less-than operator.

Template-arguments can appear other than in template-ids

There are several places where template-id is mentioned as the context in which a template-argument or template-argument-list may appear. Since that is no longer the only such context, these references are superfluous and should be deleted.

3.4.110

In a friend declaration naming a member function, a name used in the function declarator and not part of a template-argument in a template-id is first looked up in the scope of the member function's class. If it is not found, or if the name is part of a template-argument in a template-id, the look up is as described for unqualified names in the definition of the class granting friendship.

3.4.3.11, third bullet

the template-arguments of a template-id are looked up in the context in which the entire postfix-expression occurs.

Note: I think that this sentence could also stand to be editorially improved. In the first place, a template-argument may be an expression containing an arbitrary number of names, and of course only names are looked up. Also, I don't understand why we're talking about a postfix-expression here. Here's how I think it should really read, without markup:

names in a template-argument are looked up in the context in which the containing id-expression occurs.

3.4.3.21

If the nested-name-specifier of a qualified-id nominates a namespace, the name specified after the nested-name-specifier is looked up in the scope of the namespace, except that the template-arguments names in a template-argument of a template-id are looked up in the context in which the entire postfix-expression containing id-expression occurs.

14.31, second sentence

The type and form of each template-argument specified in a template-id shall match the type and form specified for the corresponding parameter declared by the template in its template-parameter-list.

Names of operator function template specializations

Most of these changes are substantially replacing a reference to template-id with a reference to template-argument-clause.

7.3.1.23, last sentence

When looking for a prior declaration of a class or a function declared as a friend, and when the name of the friend class or function is neither a qualified name nor a template-id has neither a nested-name-specifier nor a template-argument-clause, scopes outside the innermost enclosing namespace scope are not considered.

After I came up with this formulation, I realized that it assumes the resolution of core issue 355. Here's a formulation without that dependency:

When looking for a prior declaration of a class or a function declared as a friend, and when the name of the friend class or function is not a qualified name and does not have a template-argument-clause, scopes outside the innermost enclosing namespace scope are not considered.

7.3.35

A using-declaration shall not name a template-id. The unqualified-id in a using-declaration shall not include a template-argument-clause.

142, second sentence

In a function template declaration, the declarator-id shall be a template-name (i.e., not a template-id) not include a template-argument-clause.

14.21

A template specialization (14.7) can be referred to by a template-id or by an operator-function-id with a template-argument-clause:

14.23, second sentence

When parsing a template-id template-argument-clause, the first non-nested >127) is taken as the end of the template-argument-clause rather than a greater-than operator.

Note that the first sentence of this paragraph was modified above (under "The shift-reduce conflict").

14.37, first sentence

When the template in a template-id is an overloaded function template, When the identifier in a template-id refers to a set of overloaded functions, or an operator-function-id contains a template-argument-clause, both non-template functions in the overload set and function templates in the overload set for which the template-arguments do not match the template-parameters are ignored.

14.3.21, third bullet

the address of an object or function with external linkage, including function templates and function template-ids but excluding non-static class members, expressed as & id-expression where the & is optional if the name refers to a function or array, or if the corresponding template-parameter is a reference; or

As far as I can tell, the text I'm recommending to delete makes no normative difference. In any event, non-static class data member names do not have external linkage, so there is no point in specifically excluding them here. Taken on the face of it, the exclusion could also be referring to non-static class member functions, but that's clearly not the intention. As far as the inclusion is concerned, I don't think that's meant to include non-member function templates with internal linkage (see 144). So the inclusion seems to be intended only to clarify -- exactly what, I can't tell.

On the other hand, if that text really does perform some necessary function, it would probably be improved by replacing "template-ids" with "template specializations".

14.41, first sentence

Two template-ids or operator-function-ids with template-argument-clauses refer to the same class or function if their template names are identical the same (clause 3), they refer to the same template, ....

The reference is more specifically to 37.

14.51

A template-id, that is, the template-name followed by a template-argument-list template-argument-clause shall not be specified in the declaration of a primary template declaration.

14.5.31, first bullet

if the name of the friend is a qualified or unqualified template-id includes a template-argument-clause, the friend declaration refers to a specialization of a function template, otherwise

14.5.32

A friend function declaration that is not a template declaration and in which the name of the friend is an unqualified template-id name with a template-argument-clause shall refer to a specialization of a function template declared in the nearest enclosing namespace scope.

This could be formulated differently (better, in my opinion) if core issue 355 were resolved.

14.6.4.21, first sentence

For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id and has no template-argument-clause, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:

14.73, third and fourth sentences

In an explicit specialization declaration for a class template, a member of a class template or a class member template, the name of the class that is explicitly specialized shall be a template-id. In the explicit specialization declaration for a function template or a member function template, the name of the function or member function explicitly specialized may be a template-id have a template-argument-clause.

14.7.22, second sentence

If the explicit instantiation is for a class, a function or a member template specialization, the unqualified-id in the declaration shall be either a template-id or, where have a template-argument-clause, unless all template arguments can be deduced, a template-name.

14.7.311

A trailing template-argument can be left unspecified in the template-id naming template-argument-clause associated with the name of an explicit function template specialization provided it can be deduced from the function argument type.