为什么在C++20中我不需要在依赖类型前指定"typename"?

76

使用gcc 10.1编译的这段代码在C++20中编译通过,而没有在依赖类型std::vector<T>::iterator前使用typename关键字。为什么会编译通过?

#include <vector>

template<typename T>
std::vector<T>::iterator // Why does this not require "typename" before it?
f() { return {}; }

int main() {
    auto fptr = &f<int>;
}

代码沙盒


3
我有点惊讶于标准认为这里存在歧义(因此需要使用typename),因为我认为那里必须是一个类型。也许应该加上language-lawyer标签。 - Eljay
7
C++20允许删除某些typename的使用。 - Jarod42
3
@Eljay,它仍然需要知道它是一种类型;) 它作为一种类型是“那里”被定义/识别的一部分。或者说,它曾经是这样。 - Asteroids With Wings
2个回答

73
C++20中的一个新功能是Down with typename
在C++17中,你几乎必须在所有依赖上下文中提供typename关键字,以将类型与值区分开来。但是在C++20中,这个规则得到了很大放宽。在所有需要类型的上下文中,typename关键字不再是强制性的。
其中一个这样的上下文是类作用域中函数的返回类型,就像你的例子一样。其他情况包括成员声明中的类型、using声明右侧的类型、lambda参数声明、传递给static_cast的类型等。完整列表请参阅论文。

几乎所有的都被排除在外,因为基础说明符和成员初始化器ID总是被排除在外,例如:

template <typename T> struct X : T::type  { }; // always ok

这是可以的,因为那个需要成为类型。这篇论文只是将这种逻辑(必须是一种类型,所以让我们假设它是一种类型)扩展到更多必须成为类型的地方。

8
我记得在C++11中,我们已经将typename对于基类和成员初始化列表标识符中变为可选项。原始的typename提案中,在不需要时禁止使用它,但我们认为接受冗余的typename是无害的。 - MSalters

21
参考文献中得知,从c++20开始,在有明确指定为typename的依赖名称上下文中,不再需要使用typename关键字。具体而言:
在顶层的声明说明符序列(decl-specifier-seq)中用作声明说明符的限定名,例如:
- 命名空间作用域中简单声明或函数定义

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