【问题标题】:Why isn't `typename` required for a base class that is a nested type?为什么嵌套类型的基类不需要“typename”?
【发布时间】:2020-01-12 23:32:26
【问题描述】:
我很惊讶地发现,当依赖类型作为基类出现时,不需要添加typename:
struct B {};
struct wr
{ typedef B type; };
template<class T>
struct A : T::type
{};
int main()
{
A<wr> a;
(void)a;
}
为什么typename 前面不需要T::type?
【问题讨论】:
标签:
c++
templates
inheritance
【解决方案1】:
为什么typename 前面不需要T::type?
因为你不能从一个值继承。您使用 typename 告诉编译器给定的嵌套标识符是一种类型,但对于继承,无论如何都必须是这种情况,因此您可以省略它 - 这就是语言为 typename- 基本规则提供例外的原因-说明符。来自cppreference(强调我的):
typename 从属名称消歧器
在模板的声明或定义中,包括别名模板,不是当前实例化成员且依赖于模板参数的名称不被视为类型,除非使用关键字 typename 或 除非它已经被确定为类型名称,例如使用 typedef 声明或用于命名基类。
请注意,我们将获得更多可以省略typename 的地方,请参阅P0634。
【解决方案2】:
正如其他人所说,这是一种特殊情况。引用这个标准:
[温度分辨率]
5 在 class-or-decltype 或
详细说明类型说明符被隐式假定为命名一个类型,
不使用 typename 关键字。在嵌套名称说明符中
立即包含一个嵌套名称说明符,该说明符取决于
模板参数,标识符或 simple-template-id 是隐式的
假定命名一个类型,而不使用 typename 关键字。
[ 注意:这些语法不允许使用 typename 关键字
结构体。 — 尾注 ]
随着 C++20 的到来,需要typename 的例外情况会更多。
【讨论】:
-
-
@0x499602D2 - 函数返回类型、各种 *_cast 运算符的类型参数和默认模板参数。 The paper 有示例和详细信息。
【解决方案3】:
如果你需要告诉编译器期待一个类型而不是其他东西,你只需要使用typename。
由于只能继承一个类型,所以没有歧义,所以typename是多余的。