在这种情况下,关键字"typename"和"template"都不是必需的吗?

8
template<class T> 
T::type<int> f(){
    
}

根据[temp.names#3.4],
如果在不是转换函数ID的名称后面跟着“<”,则将其解释为模板参数列表的定界符,并且
- 在using-declarator中是终端名称([namespace.udecl]), - 在declarator-id中是终端名称([dcl.meaning]),或 - 在除嵌套名称说明符之外的仅类型上下文中是终端名称([temp.res])。
根据[temp.res#general-4.3.1],由于以下规则,“T :: type ”确实满足上述规则(强调我的):
如果限定或未限定名称是以下内容的终端名称,则称其处于“仅类型上下文”中:
- 在命名空间作用域中简单声明或函数定义的decl-specifier-seq的decl-specifier中, - 在类定义的成员说明符中, - 在模板头中, - 在基类说明符中, - 在成员初始化列表中, - 在catch子句中, - 在新表达式的类型-id中, - 在typeid表达式的类型-id中, - 在静态断言中的常量表达式中。

T::type<int>是模板函数f函数定义的声明符号,该函数在命名空间范围内,因此终端名称type被称为仅类型上下文。

此外,根据[temp.res#general-5]

终端名称为依赖项且位于仅类型上下文中的限定符ID被认为表示类型。

因此,由于[temp.res#general-5],限定符ID T::type<int> 被认为表示类型,而<符号被解释为模板参数列表的分隔符,由于[temp.names#3.4]。因此,这个例子应该是合法的。然而,它已被Clang和GCC拒绝。

我想知道,未来的实现是否不需要在这个例子中使用关键字typenametemplate


“template”关键字不是仍然需要用来表示模板的开始吗?我认为你只能省略内部模板类型的“template”关键字,但我仍然更喜欢保留它,因为这样更容易阅读。 - Dai
@Dai 我认为在这种情况下,不需要使用template来表示type是一个模板名称,因为根据[temp.names#3.4],它已经被明确指定为模板名称。 - xmh0511
没错,但是f是实际的函数模板。 - Dai
@Dai 是的,f 被声明为函数模板,然而,[temp.res#general-4.3.1] 只涉及 语法,它并没有提到函数定义的声明说明符。 - xmh0511
我怀疑在哪里和何时放置templatetypename关键字?可能对其中一些内容有所启发。 - WhozCraig
@WhozCraig 看起来这个答案有部分答案但不完整。 - xmh0511
1个回答

4

是的,这是规定,并且是正确的;编译器目前还没有实现(新的)template部分。在讨论这个补充时,提出了一个例子,说明在此上下文中要求关键字是荒谬的:

template<typename T> struct A {
  template<typename U> struct B {
    B();
  }; 
  template<typename U> B<U> make();
};
template<typename T> template<typename U>
A<T>::B<U>::B() {} // no 'template' keyword required before 'B' here, but...
template<typename T> template<typename U>
A<T>::B<U> A<T>::make() { return {}; } // 'template' keyword required before 'B' here?

这也说明了为什么在许多情况下不再需要使用typename的原因。 A<T>::B可能是一个依赖名称(如果声明最终表示的不是A(主模板)的成员),但这并不会干扰解析,因为那里不能出现任何表达式

由于 [temp.names#3.4] 中的 declarator-id,在 A<T>::B<U>::B() 中不需要关键字 template;在 A<T>::B<U> A<T>::make() 中也不需要关键字 template,这类似于该问题中的示例(即由于 [temp.res#general-4.3.1]), 对吗? - xmh0511
@xmh0511:是的,make 的情况类似,但它们都应该通过仅限类型的规则进行,因为构造函数声明中的第一个 B 不是 declarator-id 的终结符名称。这个规则需要进行调整,以包括嵌套的类型上下文中的 nested-name-specifier - Davis Herring
啊,我刚刚发现A <T> :: B <U> :: B中的第一个B不是declarator-id的终端名称,我在上面的注释中是错误的,看来当前草案中没有规定为什么在这种情况下可以省略template(即需要修正以涵盖此情况)。 - xmh0511
这里还有一个困惑,关于“using-declarator”的[temp.names#3.4],根据[namespace.udecl#5],using Test::tmp_id<T>应该是非法的。我不知道这里的意图是什么。这条规则只是让“<”始终成为“using-declarator”的定界符吗? - xmh0511
@xmh0511:在那里,它仍被解释为模板参数列表:只是一个不允许的模板参数列表。当然,真正的目的是用于“typename”。 - Davis Herring
也就是说,在using-declaration中可以省略typename关键字。但是,该using-declaration(包括了模板ID)本身是不合法的。 - xmh0511

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接