这里给出了关于模板消歧器的问题:
在答案中我们可以读到:
ISO C ++ 03 14.2/4
当成员模板专业化的名称出现之后。或 - >在postfix-expression中,或者在qualified-id中的nested-name-specifier之后,postfix-expression或qualified-id显式依赖于template-parameter(14.6.2),成员模板名称必须以关键字模板。否则,假定该名称命名非模板。
现在我来了一个我不太明白的例子:
template <class T>
class Base {
public:
template <int v>
static int baseGet() {return v;}
class InnerA {
public:
template <int v>
static int aget() {return v;}
};
class InnerB {
public:
typedef Base BaseType;
typedef BaseType::InnerA OtherType;
template <int v>
static int baseGet() {return BaseType::baseGet<v>();} //(A)
template <int v>
static int aget() {return OtherType::aget<v>();} //(B)
};
};
显然无法编译。您需要{B}中的template
OtherType::template aget<v>();
:template
。
但是,g ++(4.4.3)和clang ++(2.9)都没有抱怨行(A)中缺少BaseType
。为什么? T
取决于类型{{1}},不是吗?这些编译器是否与标准有所不同,或者我是否误解了标准中的某些内容?
答案 0 :(得分:8)
它们实现了C ++ 0x规范,其中Base
是当前实例化。在这种情况下,C ++ 0x允许省略template
关键字。由于BaseType
是Base
的typedef,因此当您说BaseType
时,它也会命名当前的实例化。
引用规范,因为您似乎对spec refs感兴趣
名称是当前实例化的成员,如果它是[...]
- 一个qualified-id,其中嵌套名称指定者引用当前实例化,并且当查找时,指的是当前实例化的至少一个成员或非依赖基础一类。
和
名称是指当前实例化,如果它是[...]
- 在类模板的[strong]嵌套类的定义中,[...],注入类名(第9条)类模板或嵌套类
和(你引用的修改后的14.2 / 4)
[...]或qualified-id中的nested-name-specifier引用依赖类型,但名称不是当前实例化的成员(14.6.2.1),成员模板名称必须以前缀为前缀通过关键字模板。 [...]
注意:在C ++ 03中,您的代码格式错误,因为BaseType
和OtherType
都是依赖的。规范说:
如果是[...]
,则类型是依赖的
- 模板参数
- 带有嵌套名称说明符的qualified-id,其中包含一个命名依赖类型的类名
- 模板ID,其中模板名称是模板参数或任何模板参数是依赖类型
(请注意,Base
相当于Base<T>
,Base
和BaseType::InnerA
是依赖类型的基础。
请注意,您的报价中的“明确取决于”是一个预先标准的术语,并且最近被淘汰了(我相信它是在1996年12月)。它基本上意味着(在此上下文中)限定符依赖的限定ID或a->x
依赖的类成员访问(a.x
/ a
)。从草案中删除“明确依赖”之后,它仍然潜伏在某些地方,甚至C ++ 0x仍然在14.6.2p2的注释中引用“明确依赖”:
基类名称
B<T>
,类型名称T::A
,名称B<T>::i
和pb->j
明确依赖对template-parameter。
答案 1 :(得分:1)
因为OtherType
是嵌套依赖名称,而BaseType
不是嵌套类型。
您需要将template
用于嵌套依赖类型。
这里的关键词是:
如果类型都是,那么您必须使用模板。
OtherType
是依赖类型(取决于T
)以及嵌套类型BaseType
只是依赖类型(取决于T
)。它不是嵌套类型。答案 2 :(得分:0)
BaseType
确实取决于类型T
- 但InnerB
也是如此。实际上,从BaseType<T>
内的任何代码的角度来看,它都不依赖于T
。