为什么在Visual Studio 2008/2010中不需要使用typename关键字?

6
这个问题中,提问者有以下函数:
template<typename ITER>
bool nextPermutation(ITER start, ITER end)
{
    return nextPermutation(start, end, std::iterator_traits<ITER>::iterator_category());
}

为什么在std::iterator_traits之前不需要typename? 我认为如果模板本身依赖于模板参数,则需要嵌套类型的typename。 GCC似乎支持我的想法,因为它在4.3.44.5.1下都无法编译,要求使用typename。即使如此,在Visual Studio 2008和2010下仍然可以编译正常。
这只是我不知道的另一个Visual Studio扩展/错误吗?
还是实际上可以推断出iterator_category是类型或函数,因为它后面跟着一对括号()?(请参见@DeadGM的消息从这里开始。)那么这可能实际上是GCC中的一个错误吗?

除了您列出的选项(构造函数和函数)之外,iterator_category 可以是定义了 operator() 的类型的静态成员变量。 - Sjoerd
@Sjoerd:或者一个函数指针。 - sbi
2个回答

12

Visual C++以不完全支持两阶段查找而闻名,这也是第一次需要typename的根本原因。如果编译器不完全支持此功能,则在实例化之前可能无法完全解析模板,此时它“知道”std::iterator_traits<ITER> :: iterator_category 是一种类型。显然,这种缺陷也适用于VC10。

当涉及到typename时,我更信任GCC而不是VC。


完美的答案,但我会选择@Johannes的答案,因为它更详细地解释了后期解析的事情。不过还是给你点赞。 :) - Xeo

6
MSVC是否实现了后期解析方案?在这种方案中,编译器不依赖于typename。它只是存储模板定义括号内的所有标记,并在实例化模板时解析这些标记。由于它知道什么是类型和什么不是类型,所以它可以在没有typename的情况下工作。
但是,如果编译器在实例化模板时没有诊断缺少的typename,那么它就是不符合规范的。
“iterator_category”是否可以通过其后面跟着一对括号()来推断出它是一个类型或函数?
重要的是名称是否依赖于限定符。模板能否自行推断名称始终是类型并不重要。但对于缺少typename的错误消息质量可能很重要。
顺便说一下,语言层面上无法推断任何关于iterator_category的信息。

请注意,所需的诊断可以只是一个警告。只要编译器发出至少一个警告,它就被允许“正常编译”。其次,该警告可能默认关闭 - 我所知道的所有编译器都需要存在标志或选项才能尽可能地遵循C++标准:当升级编译器时,大多数客户不希望为其旧代码添加新的警告/错误,因此向后兼容性迫使编译器编写者将新错误隐藏在其他选项后面。 - Sjoerd
@Sjoerd:标准总是只谈论“诊断”。这可以是错误或警告,两者都可以接受。 - sbi
@sbi 我相信你和 Johannes 知道,但这不是常识。 - Sjoerd

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