繁体   English   中英

实例化模板时,其不完整参数类型的成员是否应该可见?

[英]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>::AfterA模板完全解析,但是在完全创建它的特定实例化之后却没有 。实际上它将实例化它的实例化!)。

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::BeforeT::After是从属名称。

在模板定义的上下文和实例化的上下文中,在模板实例化(14.6.4.1)处查找从属名称。“ [temp.dep] / 1

我将其解释为:在实例化模板时查找它们。 他们在哪里抬头? 在模板定义的上下文和实例化的上下文中。

[temp.dep.type] / 7另一方面说:

如果对于一个给定的模板参数,模板的特化实例化是指与一个合格的-ID或类成员访问表达式,在合格-ID或类成员访问表达式的名称是当前实例中的一员在模板实例化上下文中查找。

[temp.point] / 7定义实例化上下文 ,如下所示:

依赖于模板参数的表达式的实例化上下文是在同一翻译单元中模板特化的实例化之前声明的具有外部链接的声明集。

因此,我们需要知道实例化的重点。

[temp.point / 4

对于类模板特化[...],如果特化是隐式实例化的,因为它是从另一个模板特化中引用的,如果引用特化的上下文取决于模板参数,并且如果特化没有实例化,则对于封闭模板的实例化,实例化的点紧接在封闭模板的实例化之前。

虽然注入的类名 A可以说是 依赖于 (作为外行术语) A的模板参数的上下文,但名称 A本身不是依赖名称。 Johannes Schaub的更正:这一个从属名称。 参见[temp.local] / 1和[temp.dep.type] / 8 => A是从属类型。

因此,该条件 不满足 ,和B<A>应之前被实例A<int>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM