[英]When instantiating a template, should members of its incomplete argument types be visible?
在以下示例中, 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
不是。 这种行为是否符合标准? 如果是这样,标准在哪里指定在实例化B<A>
期间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中看到任何明确描述这种行为的东西。 最接近的是这个有点模糊的段落:
[temp.dep.res]在解析依赖名称时,会考虑以下来源的名称:
- 在模板定义点可见的声明。
是否有typename T::Before
有效未被规范明确说明。 它是缺陷报告的主题(因为可以非常合理地阅读标准以禁止它): http : //www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#287 。
typename T::After
是否无效也可以通过规范非常合理地读取,实际上它有点意义(并且前面提到的DR仍然使其不正确)。 因为你有一个类A<Foo>
的实例化,它在一个尚未声明成员Baz
的时间段内引用另一个类A<Bar>
,并且引用回A<Foo>::Bar
。 这是病态的非模板藏汉的情况下(试图“忘记”您所处理的模板了一下:肯定的查找B<A>::After
是后做A
模板完全解析,但是在完全创建它的特定实例化之后却没有 。实际上它将实例化它的实例化!)。
struct A {
typedef int Foo;
typedef A::Foo Bar; // valid
typedef A::Baz Lulz; // *not* valid
typedef int Baz;
};
由于[temp.dep.type] / 8和/ 5, T::Before
和T::After
是从属名称。
在模板定义的上下文和实例化的上下文中,在模板实例化(14.6.4.1)处查找从属名称。“ [temp.dep] / 1
我将其解释为:在实例化模板时查找它们。 他们在哪里抬头? 在模板定义的上下文和实例化的上下文中。
[temp.dep.type] / 7另一方面说:
如果对于一个给定的模板参数,模板的特化实例化是指与一个合格的-ID或类成员访问表达式,在合格-ID或类成员访问表达式的名称是当前实例中的一员在模板实例化上下文中查找。
[temp.point] / 7定义实例化上下文 ,如下所示:
依赖于模板参数的表达式的实例化上下文是在同一翻译单元中模板特化的实例化之前声明的具有外部链接的声明集。
因此,我们需要知道实例化的重点。
[temp.point / 4
对于类模板特化[...],如果特化是隐式实例化的,因为它是从另一个模板特化中引用的,如果引用特化的上下文取决于模板参数,并且如果特化没有实例化,则对于封闭模板的实例化,实例化的点紧接在封闭模板的实例化之前。
虽然注入的类名
Johannes Schaub的更正:这是一个从属名称。 参见[temp.local] / 1和[temp.dep.type] / 8 => A
可以说是
依赖于 (作为外行术语)
A
的模板参数的上下文,但名称
A
本身不是依赖名称。
A
是从属类型。
因此,该条件
不满足
,和B<A>
应之前被实例A<int>
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.