在以下示例中,A
有一个成员 typedefInstantiate
会导致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] 在查找模板定义中使用的名称声明时,通常的查找规则用于非依赖名称。依赖于模板参数的名称查找被推迟,直到知道实际的模板参数。
因此,查找 ofT::After
被推迟到T
知道 for 的参数为止。
[temp.inst] 除非已显式实例化类模板特化......当在需要完全定义的对象类型的上下文中引用特化时,类模板特化被隐式实例化。
因此,声明A<int>::Instantiate
需要实例化B<A>
(因为它在嵌套名称说明符中使用。)
A<int>::After
在声明时不可见A<int>::Instantiate
,因此编译器的行为是有意义的——但我在 C++03 中没有看到任何明确描述这种行为的东西。最接近的是这个有点模糊的段落:
[temp.dep.res] 在解析从属名称时,会考虑以下来源的名称:
— 在模板定义时可见的声明。