考虑以下程序:
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:
以关键字为前缀的名称
template应为模板 ID,或者名称应指类模板或别名模板。[ <em>注意:关键字template可能不适用于类模板的非模板成员。— <em>end note ] [ <em>注意:与typename前缀的情况一样,在不是严格必要的情况下允许使用template前缀;即,当嵌套名称说明符或or左侧的表达式不依赖于模板参数,或者使用未出现在模板范围内时。— <em>结束注释]->.
并且由于[temp.names]/4管辖的禁令不适用:
如果关键字出现在template-argument-list或decltype-specifier之外,则称该关键字出现在qualified-id
template的顶层。[...]出现在顶层的可选关键字被忽略。[...]template
并且,最多只声明关键字应该被忽略(而不是程序格式错误)。
我在[class.conv.fct]或[temp.deduct.conv]中没有发现任何与此论点相冲突的子句。
问题
template使用关键字作为对转换函数模板的显式访问前缀是否合法?
我已经针对各种语言标准版本使用各种GCC和Clang版本测试并重复了上述编译器的行为,但是对于这个问题的范围,我们可能会关注-std=c++17.