当前的C ++编译器(最新的gcc,clang)需要以下示例中的typename
关键字:
template<class T>
struct A
{
};
template<class T>
void f(T)
{
struct C
{
};
typedef typename A<C>::Type Type; // typename required
}
如果省略typename
,gcc(4.9,5.0)会报告错误:
need 'typename' before 'A<f(T)::C>::Type' because 'A<f(T)::C>' is a dependent scope
根据我对C ++ 11标准的阅读,这个例子结构良好。
以下措辞似乎涵盖了这种行为:
[temp.dep.type] / 8
如果类型是
,则类型是依赖的
模板参数
未知专业化的成员,
作为当前实例化成员的嵌套类或枚举,
cv-qualified类型依赖的cv限定类型,
由任何依赖类型构建的复合类型
从任何依赖类型构造的数组类型或其大小由常量表达式指定 这是依赖于价值的,
一个simple-template-id,其中模板名称是模板参数或任何模板 arguments是依赖类型或依赖于类型或依赖于值的表达式,或
由decltype(表达式)表示,其中表达式取决于类型。
但是,根据[class.local],类C
是本地类,而不是嵌套类。如果是这样,为什么A<C>
应被视为依赖?
修改
对于奖励积分,如果通过向C
添加成员枚举来修改示例,如下所示:
template<typename T>
struct A
{
typedef T Type;
};
template<class T>
void f(T)
{
struct C
{
enum { value = T::value };
};
typedef typename A<C>::Type Type; // typename required
}
A<C>
现在应该被视为依赖吗?
答案 0 :(得分:4)
根据我的理解(以及标准的当前措辞),您的示例中的C
不依赖。这两项都不是A<C>::Type
,因此不需要typename
。
类模板的嵌套类与函数模板中的本地类之间存在根本区别:后者不能专门化,因此对函数模板内的本地类的任何引用都是统一的。也就是说,在f
的每个专精中,C
指的是此函数模板C
中定义的类f
。类模板的情况并非如此,因为您确实可以自己明确地专门化成员(如[temp.expl.spec]所述)
/(1.6)):
template <typename T>
class A { class C{}; };
template <>
class A<int>::C { int i; };
然而:
如果类型是
,则类型是依赖的
- 由任何依赖类型构建的复合类型,
因此,如果定义是在dyp's example中完成的,那么C
将依赖T
构建。
在评论部分讨论的标准措辞中存在不明确之处,例如:关于依赖于T
的成员函数的定义以及如何转换为类依赖项。
答案 1 :(得分:0)
以下是我的推理,希望它有所帮助。在C
实例化之前,本地f
不会实例化。因此,A<C>
不是实例化,并且在看到它时对编译器是不透明的。由于不透明性,编译器无法确定A<C>::Type
是嵌套类型名称还是数据成员或方法。但是,默认情况下,编译器不会将A<C>::Type
视为嵌套类型名称。因此,需要明确的规范。
答案 2 :(得分:0)
标准中似乎没有任何内容表明此处需要typename
关键字。这些措辞也没有明确说明,这可能导致海湾合作委员会采取一些捷径来处理f<T>(T)::C
(在函数模板专业化中是一个本地类)依赖于T
- 扩展,这会使A<[f<T>(T)::]C>::Type
依赖。
Core defect 1484没有具体针对这个问题提出,但我认为它提出的其他非规范性文本使得意图明确,如果它是标准的,GCC将完全不需要{{1}这里有关键字。