使用 'template' 关键字前缀显式访问转换函数模板是否合法?
Is it legal to prefix explicit access to a conversion function template with the 'template' keyword?
考虑以下程序:
struct A {
template <typename T>
operator T() { return T{}; }
};
int main() {
(void) A{}.operator int(); // (A)
(void) A{}.template operator int(); // (B)
}
(A) 被 GCC 和 Clang 接受,而 (B) 仅被 GCC 接受但被 Clang 拒绝并出现以下错误消息:
error: expected template name after 'template' keyword in nested name specifier
(void) A{}.template operator int(); // (B)
^~~~~~~~~~~~
Afaict,(B) 应该是合法的,根据 [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 ]
并且由于 [temp.names]/4 规定的禁令不适用:
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. [...]
并且最多只声明应忽略该关键字(而不是程序格式错误)。
我没有在 [class.conv.fct] or [temp.deduct.conv] 中找到任何与此论点冲突的条款。
问题
- 在显式访问转换函数模板前加上
template
关键字是否合法?
我已经针对各种语言标准版本使用各种 GCC 和 Clang 版本测试并重复了上述编译器的行为,但是对于这个问题的范围,我们可能会关注 GCC 10.1.0 和 Clang 10.0.0 for -std=c++17
.
GCC接受程序错误:转换函数模板名(conversion-function-id)不是template-id
这是 CWG Defect Report 96, which has, as of GCC 10, has not yet been addressed. The related bug GCC ticket 55588 提到它正在为 GCC 11 实现。
如对 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
因此,正如 OP 中引用的那样,根据 [temp.names]/5,template
关键字不得用于作为转换函数模板名称的前缀,因为后者不是 template-id.
有趣的是,Clang 在引用 operator-function-id(是一个模板ID):
struct A {
template <typename T>
T operator+() { return T{}; }
};
int main() {
(void) A{}.operator+<int>(); // (A)
(void) A{}.template operator+<int>(); // (B)
}
如上所述,GCC 接受 OP 的程序是一个错误,因为它违反了 [temp.names]/5。
考虑以下程序:
struct A {
template <typename T>
operator T() { return T{}; }
};
int main() {
(void) A{}.operator int(); // (A)
(void) A{}.template operator int(); // (B)
}
(A) 被 GCC 和 Clang 接受,而 (B) 仅被 GCC 接受但被 Clang 拒绝并出现以下错误消息:
error: expected template name after 'template' keyword in nested name specifier (void) A{}.template operator int(); // (B) ^~~~~~~~~~~~
Afaict,(B) 应该是合法的,根据 [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 keywordtemplate
may not be applied to non-template members of class templates. — end note ] [ Note: As is the case with thetypename
prefix, thetemplate
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 ]
并且由于 [temp.names]/4 规定的禁令不适用:
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 keywordtemplate
appearing at the top level is ignored. [...]
并且最多只声明应忽略该关键字(而不是程序格式错误)。
我没有在 [class.conv.fct] or [temp.deduct.conv] 中找到任何与此论点冲突的条款。
问题
- 在显式访问转换函数模板前加上
template
关键字是否合法?
我已经针对各种语言标准版本使用各种 GCC 和 Clang 版本测试并重复了上述编译器的行为,但是对于这个问题的范围,我们可能会关注 GCC 10.1.0 和 Clang 10.0.0 for -std=c++17
.
GCC接受程序错误:转换函数模板名(conversion-function-id)不是template-id
这是 CWG Defect Report 96, which has, as of GCC 10, has not yet been addressed. The related bug GCC ticket 55588 提到它正在为 GCC 11 实现。
如对 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
因此,正如 OP 中引用的那样,根据 [temp.names]/5,template
关键字不得用于作为转换函数模板名称的前缀,因为后者不是 template-id.
有趣的是,Clang 在引用 operator-function-id(是一个模板ID):
struct A {
template <typename T>
T operator+() { return T{}; }
};
int main() {
(void) A{}.operator+<int>(); // (A)
(void) A{}.template operator+<int>(); // (B)
}
如上所述,GCC 接受 OP 的程序是一个错误,因为它违反了 [temp.names]/5。