Is it legal to prefix explicit access to a conversion function template with the 'template' keyword?

Viewed 135

Consider the following program:

struct A {
    template <typename T>
    operator T() { return T{}; }
};

int main() {
    (void) A{}.operator int();          // (A)
    (void) A{}.template operator int(); // (B)
}

(A) is accepted by both GCC and Clang, whereas (B) is accepted only by GCC but rejected by Clang with the following error message:

error: expected template name after 'template' keyword in nested name specifier

(void) A{}.template operator int(); // (B)
                    ^~~~~~~~~~~~

Afaict, (B) should be legal, as per [temp.names]/5:

A name prefixed by the keyword template shall be a template-id or the name shall refer to a class template or an alias template. [ 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 ]

and as the prohibitions governed by [temp.names]/4 does not apply:

The keyword template is said to appear at the top level in a qualified-id if it appears outside of a template-argument-list or decltype-specifier. [...] an optional keyword template appearing at the top level is ignored. [...]

and, at most, only state that the keyword should be ignored (but not that the program is ill-formed).

I have not found any clause in [class.conv.fct] or [temp.deduct.conv] that conflicts with this argument.

Question

  • Is it legal to prefix explicit access to a conversion function template with the template keyword?

I have tested and repeated the compilers' behaviour above with various GCC and Clang versions for various language standard versions, but for the scope of this question, we may focus on GCC 10.1.0 and Clang 10.0.0 for -std=c++17.

1 Answers

GCC is wrong to accept the program: a conversion function template name (conversion-function-id) is not a template-id

This is CWG Defect Report 96, which has, as of GCC 10, has not yet been addressed. The related bug GCC ticket 55588 mentions that it is being implemented for GCC 11.


As is covered in the answer to Is it possible to call templated user-defined conversion operator with explicit template arguments?, a conversion function template name does not name a template-id; quoting the grammar from template-id from [temp.names]/1:

simple-template-id:
  template-name < template-argument-list_opt>

template-id:
  simple-template-id
  operator-function-id < template-argument-list_opt>
  literal-operator-id < template-argument-list_opt>

template-name:
  identifier

Thus, as is quoted in the OP, as per [temp.names]/5, the template keyword may not be used to prefix the name of a conversion function template, as the latter is not a template-id.

It may be interesting to point out that Clang does not reject using the keyword when referring to an operator-function-id (which is a template-id):

struct A {
    template <typename T>
    T operator+() { return T{}; }
};

int main() {
    (void) A{}.operator+<int>();          // (A)
    (void) A{}.template operator+<int>(); // (B)
}

That GCC accepts the OP's program is, as covered above, a bug, as it violates [temp.names]/5.

Related