为什么这个模板代码会编译?

Bar*_*rry 8 c++ templates

我正在开发一个大型项目,其中包含一段编译的代码 - 但我不明白如何.我把它简化为这个简单的例子:

template <typename T>
struct First {
    typedef int type;           // (A)
    typename T::Three order;    // (B)
};

template <typename T> struct Second {
    typedef typename T::type type;
};


template <typename T> struct Third {
    int val;
    T two;
};

struct Traits {
    typedef First<Traits> One;
    typedef Second<One> Two;
    typedef Third<Two> Three;
};

int main(int argc, char** argv) {
    Traits::One x;
};
Run Code Online (Sandbox Code Playgroud)

这个类First是模板上Traits和引用Traits::Three,这本身就是一个typedef基于Two,这是一个typedef基于First<Traits>...因此它是圆形的.但是这个代码在gcc4.6和VC10上编译都很好.但是,如果我翻转标志着两行的排序(A)(B),代码不编译,抱怨typedef的内部Second.

为什么这段代码会编译,为什么typedef和成员变量的排序很重要?

Sha*_*kos 3

有几件事值得一说。

  • Second如果修改为包含该代码将中断

    T badObject;
    
    Run Code Online (Sandbox Code Playgroud)

    由于您期望的循环性,有一个很长的“实例化自...”链并以“不完整类型”错误结束,但如果您添加

    typename T::type object;
    
    Run Code Online (Sandbox Code Playgroud)

    这告诉你编译器很聪明地观察它不需要完全封装T,只需要知道T::type是什么。为了说明这一点,请注意您可以合法地拥有

    First { ... typedef T type; ... }
    Second { typename T::type object; }
    
    Run Code Online (Sandbox Code Playgroud)

    因为 T 不包含当前正在定义的对象,或者

    First { ... typedef typename T::One type; ... }
    Second { typedef typename T::type object; }
    
    Run Code Online (Sandbox Code Playgroud)

    因为typedefinSecond也不需要任何对象的实例 - 但不是,比如说,

    First { ... typedef typename T::One type; ... }
    Second { typename T::type object; }
    
    Run Code Online (Sandbox Code Playgroud)

    因为只有这样,编译器才真正需要将First<Traits>对象嵌套在First<Traits>对象中。

  • 交换 (A) 和 (B) 的问题在于,编译器上面提出的巧妙技巧是通过引入每个专用模板定义的新副本,一次解析它一行First如果在需要通过 来了解类型定义时,如果尚未达到类型定义,则会发生错误Second