我正在处理一个大型项目,其中包含一段可以编译的代码 - 但我不明白如何编译。我将其提炼为这个简单的示例:
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;
};
类(class)First
以 Traits
为模板和引用文献 Traits::Three
,它本身就是一个 typedef
基于 Two
,这是一个 typedef
基于 First<Traits>
...因此它是循环的。但是这段代码在 gcc4.6 和 VC10 上都编译得很好。但是,如果我翻转标记为 (A)
的两行的顺序和 (B)
,代码无法编译,提示 typedef
Second
内部.
为什么这段代码可以编译,为什么 typedef
的顺序是这样的?成员变量很重要吗?
最佳答案
有几件事值得一提。
如果
Second
,代码将中断被修改为包含T badObject;
有一个很长的“实例化自...”链并以“不完整类型”错误结尾,这是由于您期望的循环性,但如果您改为添加则不会
typename T::type object;
这是在告诉你编译器在巧妙地观察它不需要完全封装
T
,才知道是什么T::type
是。为了说明这一点,请注意您可以合法拥有First { ... typedef T type; ... } Second { typename T::type object; }
因为 T 不包含当前定义的对象,或者
First { ... typedef typename T::One type; ... } Second { typedef typename T::type object; }
自
typedef
在Second
也不需要任何对象的实例 - 但不需要,比如说,First { ... typedef typename T::One type; ... } Second { typename T::type object; }
因为只有这样,编译器才真正需要嵌套
First<Traits>
First<Traits>
中的对象对象。交换 (A) 和 (B) 的问题在于,编译器在上面采用的巧妙技巧是通过引入每个专用模板定义的新拷贝来工作的,一次解析它的一行时间。如果它没有达到
First
中的类型定义,就会发生错误当需要通过Second
了解它时.
关于c++ - 为什么这个模板代码可以编译?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15935461/