【发布时间】:2013-07-02 22:49:35
【问题描述】:
在下面的示例中,A 有一个成员 typedef Instantiate,它会导致 B<A> 的实例化。
template<typename T>
struct B
{
typedef typename T::Before Before; // ok
typedef typename T::After After; // error: no type named 'After' in 'A<int>'
};
template<typename T>
struct A
{
typedef int Before;
typedef typename B<A>::After Instantiate;
typedef int After;
};
template struct A<int>; // instantiate A<int>
我尝试过的所有编译器都报告说,A::Before 可见,A::After 不可见。这种行为是否符合标准?如果是这样,标准在哪里指定A 中的哪些名称应该在B<A> 的实例化期间可见?
如果从属名称“在模板实例化点查找”,那么在T::After 等模板参数限定名称的场景中,这意味着什么?
编辑:请注意,当 A 不是模板时会发生相同的行为:
template<typename T>
struct B
{
typedef typename T::Before Before; // ok
typedef typename T::After After; // error: no type named 'After' in 'A'
};
struct A
{
typedef int Before;
typedef B<A>::After Instantiate;
typedef int After;
};
.. 和 G++ 接受以下内容,但 Clang 不接受:
template<typename T>
struct B
{
static const int value = 0;
static const int i = T::value; // clang error: not a constant expression
};
struct A
{
static const int value = B<A>::value;
};
编辑:阅读 C++03 标准后:
[temp.dep.type] 类型是依赖的,如果它是一个模板参数
因此T 是依赖的。
[temp.res] 在查找模板定义中使用的名称声明时,通常的查找规则用于非依赖名称。依赖于模板参数的名称查找被推迟到知道实际的模板参数。
T::After 的查找因此被推迟,直到知道T 的参数为止。
[temp.inst] 除非已显式实例化类模板特化......当在需要完全定义的对象类型的上下文中引用特化时,类模板特化将被隐式实例化。
因此A<int>::Instantiate 的声明需要B<A> 的实例化(因为它用于嵌套名称说明符中。)
A<int>::After 在声明A<int>::Instantiate 时不可见,因此编译器的行为是有道理的——但我在 C++03 中没有看到任何明确描述此行为的内容。最接近的是这个有点模糊的段落:
[温度.dep.res] 在解析从属名称时,会考虑来自以下来源的名称:
——在模板定义处可见的声明。
【问题讨论】:
-
我会说这些是从属名称 [temp.dep],它们在模板的实例化点 [temp.dep]/1 -> [temp.point]
-
我把那段读了一百遍,但直到现在才有意义..
-
@DyP 你应该这样回答 ;)
-
@DyP:我同意 Obvlious 船长的观点。
-
嗯,不,我认为在不完整类型的名称查找中仍然缺少一些东西;但我可能错了。
标签: c++ templates language-lawyer