7

在以下示例中,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] 在解析从属名称时,会考虑以下来源的名称:

— 在模板定义时可见的声明。

4

2 回答 2

4

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

是否typename T::After无效也可以非常合理地被规范解读为真实,实际上它很有道理(并且前面提到的 DR 仍然保持它的格式不正确)。因为您有一个 class 的实例化,它在尚未声明成员的期间A<Foo>引用另一个类,并且引用回. 这在非模板的情况下也是不正确的(尝试“忘记”你正在处理模板的片刻:肯定是在模板完全解析后完成查找,而不是在它的特定实例化之后完成是完全创建的。它的实例化实际上会做引用!)。A<Bar>BazA<Foo>::BarB<A>::AfterA

struct A {
   typedef int Foo;
   typedef A::Foo Bar; // valid
   typedef A::Baz Lulz; // *not* valid
   typedef int Baz; 
};
于 2013-07-05T22:58:13.073 回答
2

T::Before并且T::After由于 [temp.dep.type]/8 和 /5 而成为依赖名称。

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

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

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

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

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

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

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

[温度点]/4

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

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

所以这个条件不满足 应该B<A>先实例化A<int>

于 2013-07-04T23:07:39.943 回答