From: http://blog.csdn.net/aladdina/archive/2009/03/03/3953552.aspx
上午 Randy同学碰到了一个 array中应用 tr1::is_pod导致的编译错误,看了一下,顺便了解了一些概念:
在开始之前,还是说说什么是 tr1。
TR1 ,全称是“ C++ Technical Report 1”,实际上是 C++标准扩展库 ISO/IEC TR 19768的一个俗称,是进入 C++标准库的一个提案。 TR1中包括的内容主要有:正则表达式 (regular expressions)、智能指针 (smart pointers),哈希表 (hash tables)以及随机数产生器 (random number generators),还包括函数对象 (Function Objects),元编程和类型属性 (Metaprogramming and Type Traits)等等很多内容。 TR1本身并不是 C++标准,而是一个草案。但是绝大多数情况下提案的内容都会成为下一个官方标准。
参见 :
http://en.wikipedia.org/wiki/Technical_Report_1
下面说说我们使用 is_pod相关的东西。
POD : 全称是“ Plain Old Data”,是 C++ 98标准 (ISO/IEC 14882, first edition, 1998-09-01)中引入的一个概念,主要目的是兼容 C和 C++语言中对数据的比较。实质上 POD类型主要包括 int, char, float等原始类型及其集合类型 (aggregate class) 。
参见:
http://en.wikipedia.org/wiki/Plain_Old_Data_Structures
http://www.fnal.gov/docs/working-groups/fpcltf/Pkg/ISOcxx/doc/POD.html
POD Aggregate Class: 上面刚提到,就是一个只包含 POD 数据的类,不使用 C++ 中的封装和面向对象的特性。其中还包含的意思是说, POD 的定义是可以迭代的,如果一个类只包含 POD 数据,那这个类就属于 POD 。以此类推,如果一个类只包含 POD 数据或者 POD 类,那它也属于 POD 。
最后在说到 is_pod之前,说说 Randy同学碰到的编译错误:
error C2139: an undefined class is not allowed as an argument to compiler intrinsic type trait '__has_trivial_constructor'
Trivial Constructor:我们经常可以有看到 trivial之类的词,到底是什么意思呢?如果去查词典,估计很难理解。个人的理解,就是轻量级的,类似于“浅拷贝”中的“浅”,或许是更浅的浅。 Trivial Constructor其实是说更本不允许用户自己定义 constructor,即使自己定义的 constructor是一个空函数都不行。当然,定义虚函数也不行,因为虚函数会导致编译器自动生成的 constructor中 包含额外的操作。(这里trivial constructor也是个人不太明确的问题,本意应该是说更本没有constructor,但是MSDN的定义 是:__has_trivial_constructor(type): Returns true if the type has a trivial, compiler-generated constructor。因此个人觉得可以理解成,没有constructor,但是不能阻止编译器在实现的时候有自定义的设置)
最后终于说到 is_pod了,因为使用的是 MS的编译器,因此看看 MSDN中的解释:
An instance of the type predicate holds true if the type Ty is a scalar type, a POD aggregate type, or a cv-qualified form of one of them, or an array of such a type, otherwise it holds false.
其中还有一个概念“ cv-qualified”,看到不同的地方有很多争议,个人觉得这个其实很简单,就是是否可以用 const或者 volatile修饰。如果可以则是 cv-qualified,否则是 cv-unqualified。那么你可能会问,还有什么变量不能用 const或者 volatile来修饰呢?请在下面的例子中查找答案。
因此,最后,希望大家可以理解 MSDN中那么短短的一句话。
(额外说明:不同的编译器对于 is_pod的实现不一定是相同的,这里是用 Visual Studio 2008 SP1的编译器来测试的,而且 boost中的实现也针对编译器的不同做了不同的定义)
下面有 12个实例来说明
#include <iostream> #include <type_traits>
// === 属于 POD 的对象 ===
// 没有定义任何数据成员 class pod_yes_1 {};
// 定义了一个元数据类型的公有成员变量 class pod_yes_2 { public : int a ; };
// 定义了一个元数据类型以及一个 POD 对象 class pod_yes_3 { public : float a ; pod_yes_2 b ; };
// 定义了 1 个 POD 对象以及一个迭代的 POD 对象 class pod_yes_4 { public : float a ; pod_yes_2 b ; pod_yes_3 c ; };
// === 不属于 POD 的对象 ===
// 从一个 POD 对象派生 class pod_no_1 : public pod_yes_1 {}; class pod_no_2 : public pod_yes_2 {};
// 虚拟继承,更不行了,而且不符合 "trivial constructor" 的要求 class pod_no_3 : virtual public pod_yes_1 {};
// 定义了一个私有(或者保护)类型的成员变量 class pod_no_4 { int a ; };
// 定义了构造函数,虽然是空的,仍然不符合 "trivial constructor" 的要求 class pod_no_5 { public : pod_no_5 (){} };
// 定义了虚函数,不符合 "trivial constructor" 的要求 class pod_no_6 { public : virtual void foo (){} };
// 父类定义了构造函数:不符合 "trivial constructor" 的要求 class pod_no_7 : public pod_no_5 {};
// PodRef 不是 cv-qualified 的对象,看到这里知道上面问题的答案了吧。也意味着不符合 "trivial constructor" 的要求。 // warning C4510: 'pod_no_8' : default constructor could not be generated // warning C4512: 'pod_no_8' : assignment operator could not be generated // warning C4610: class 'pod_no_8' can never be instantiated - user defined constructor required typedef pod_yes_1 & PodRef ; class pod_no_8 { public : PodRef x ;};
template < typename T1 > class testpod { public : testpod (){ std :: cout << typeid ( T1 ). name ()<< "/tPOD: " <<( std :: tr1 :: is_pod < T1 >:: value ? "yes" : "no " ); std :: cout << "/tTrivial Constructor: " <<( __has_trivial_constructor ( T1 )? "yes" : "no" )<< std :: endl ; } };
void main () { testpod < pod_yes_1 >(); testpod < pod_yes_2 >(); testpod < pod_yes_3 >(); testpod < pod_yes_4 >(); testpod < pod_no_1 >(); testpod < pod_no_2 >(); testpod < pod_no_3 >(); testpod < pod_no_4 >(); testpod < pod_no_5 >(); testpod < pod_no_6 >(); testpod < pod_no_7 >(); testpod < pod_no_8 >();
pod_yes_1 pod1 ; const PodRef r1 = pod1 ; // warning C4181: qualifier applied to reference type; ignored volatile PodRef r2 = pod1 ; // warning C4181: qualifier applied to reference type; ignored } |
程序输出:
class pod_yes_1 POD: yes Trivial Constructor: yes
class pod_yes_2 POD: yes Trivial Constructor: yes
class pod_yes_3 POD: yes Trivial Constructor: yes
class pod_yes_4 POD: yes Trivial Constructor: yes
class pod_no_1 POD: no Trivial Constructor: yes
class pod_no_2 POD: no Trivial Constructor: yes
class pod_no_3 POD: no Trivial Constructor: no
class pod_no_4 POD: no Trivial Constructor: yes
class pod_no_5 POD: no Trivial Constructor: no
class pod_no_6 POD: no Trivial Constructor: no
class pod_no_7 POD: no Trivial Constructor: no
class pod_no_8 POD: no Trivial Constructor: no