我正在开发一个大型项目,其中包含一段编译的代码 - 但我不明白如何.我把它简化为这个简单的例子:
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和成员变量的排序很重要?
有几件事值得一说。
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。
| 归档时间: |
|
| 查看次数: |
239 次 |
| 最近记录: |