CWG Issue 96 (original) (raw)

This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 118e. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2025-11-05


96. Syntactic disambiguation using the template keyword

Section: 13.3 [temp.names]Status: C++11Submitter: John SpicerDate: 16 Feb 1999

[Voted into WP at August, 2010 meeting.]

The following is the wording from 13.3 [temp.names] paragraphs 4 and 5 that discusses the use of the "template" keyword following. or -> and in qualified names.

When the name of a member template specialization appears after .or -> in a postfix-expression, or after _nested-name-specifier_in a qualified-id, and the postfix-expression or _qualified-id_explicitly depends on a template-parameter(13.8.3 [temp.dep] ), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template. [Example:

class X {
public:
    template<std::size_t> X* alloc();
    template<std::size_t> static X* adjust();
};

template<class T> void f(T* p) {
    T* p1 = p->alloc<200>();
            // ill-formed: < means less than

    T* p2 = p->template alloc<200>();
            // OK: < starts template argument list

    T::adjust<100>();
            // ill-formed: < means less than

    T::template adjust<100>();
            // OK: < starts explicit qualification
}

—_end example_]

If a name prefixed by the keyword template is not the name of a member template, the program is ill-formed. [Note: the keyword templatemay not be applied to non-template members of class templates. ]

The whole point of this feature is to say that the "template" keyword is needed to indicate that a "<" begins a template parameter list in certain contexts. The constraints in paragraph 5 leave open to debate certain cases.

First, I think it should be made more clear that the template name must be followed by a template argument list when the "template" keyword is used in these contexts. If we don't make this clear, we would have to add several semantic clarifications instead. For example, if you say "p->template f()", and "f" is an overload set containing both templates and nontemplates: a) is this valid? b) are the nontemplates in the overload set ignored? If the user is forced to write "p->template f<>()" it is clear that this is valid, and it is equally clear that nontemplates in the overload set are ignored. As this feature was added purely to provide syntactic guidance, I think it is important that it otherwise have no semantic implications.

I propose that paragraph 5 be modified to:

If a name prefixed by the keyword template is not the name of a member template, or an overload set containing one or more member templates, the program is ill-formed. If the name prefixed by the templatekeyword is not followed by a template-argument-list, the program is ill-formed.

(See also issue 30 and document J16/00-0008 = WG21 N1231.)

Notes from 04/00 meeting:

The discussion of this issue revived interest in issues11 and 109.

Notes from the October 2003 meeting:

We reviewed John Spicer's paper N1528 and agreed with his recommendations therein.

Proposed resolution (February, 2010):

Change 13.3 [temp.names] paragraph 5 as follows:

If a A name prefixed by the keywordtemplate is not the name of a template, shall be a template-id or the name shall refer to a class template the program is ill-formed. [Note: the keyword template may not be applied to non-template members of class templates. —_end note_] [Note: as is the case with the typename prefix, the template prefix is allowed in cases where it is not strictly necessary; i.e., when the _nested-name-specifier_or the expression on the left of the -> or .is not dependent on a template-parameter, or the use does not appear in the scope of a template. —_end note_][Example:

template struct A { void f(int); template void f(U); };

template void f(T t) { A a; a.template f<>(t); // OK: calls template a.template f(t); // error: not a template-id }

template struct B {template struct C {}; }; // OK: T::template C names a class template: template <class T, template class TT = T::template C> struct D {}; D<B> db;

—_end example_]