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

时间:2013-07-04 22:02:39

标签: c++ templates language-lawyer

在以下示例中,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中看到任何明确描述此行为的内容。最接近的是这个有点模糊的段落:

  

[temp.dep.res]   在解析从属名称时,会考虑以下来源的名称:

     

- 在模板定义点可见的声明。

2 个答案:

答案 0 :(得分:4)

规范没有明确说明typename T::Before是否有效。它是缺陷报告的主题(因为可以非常合理地阅读标准以禁止它):http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#287

typename T::After是否无效也可以通过规范非常合理地读取,实际上它有点意义(并且前面提到的DR仍然使其形成错误)。因为您有一个类A<Foo>的实例化,它在尚未声明成员A<Bar>的时间段内引用另一个类Baz,并且引用回{{1} }}。在非模板的情况下,这也是不正确的(尝试“忘记”你正在处理模板的时刻:肯定A<Foo>::Bar的查找在之后完成 { {1}}模板已完全解析,但在完全创建它的特定实例化之后。实际上它将实例化它的实例化。)。

B<A>::After

答案 1 :(得分:2)

由于[temp.dep.type] / 8和/ 5,

T::BeforeT::After是从属名称。

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

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

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

  

对于给定的模板参数集,如果实例化模板的特化,该模板的特化引用具有 qualified-id 或类成员访问表达式的当前实例化的成员,则名称为在模板实例化上下文中查找 qualified-id 或类成员访问表达式。

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

  

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

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

[temp.point / 4

  

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

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

因此,此条件 已完成,A应在B<A>之前实例化。