CPP POD

来源:互联网 发布:python os.system 参数 编辑:程序博客网 时间:2024/04/29 02:07

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 TypeTraits)等等很多内容。TR1本身并不是C++标准,而是一个草案。但是绝大多数情况下提案的内容都会成为下一个官方标准。

参见:

http://en.wikipedia.org/wiki/Technical_Report_1

 

下面说说我们使用is_pod相关的东西。

POD: 全称是“PlainOld Data”,是C++ 98标准(ISO/IEC 14882, first edition,1998-09-01)中引入的一个概念,主要目的是兼容CC++语言中对数据的比较。实质上POD类型主要包括int, char, float等原始类型及其集合类型(aggregateclass)

参见:

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 anargument to compiler intrinsic type trait '__has_trivial_constructor'

Trivial Constructor:我们经常可以有看到trivial之类的词,到底是什么意思呢?如果去查词典,估计很难理解。个人的理解,就是轻量级的,类似于“浅拷贝”中的“浅”,或许是更浅的浅。TrivialConstructor其实是说更本不允许用户自己定义constructor,即使自己定义的constructor是一个空函数都不行。当然,定义虚函数也不行,因为虚函数会导致编译器自动生成的constructor中包含额外的操作。(这里trivialconstructor也是个人不太明确的问题,本意应该是说更本没有constructor,但是MSDN的定义是:__has_trivial_constructor(type): Returns true if the type has atrivial, compiler-generatedconstructor。因此个人觉得可以理解成,没有constructor,但是不能阻止编译器在实现的时候有自定义的设置)

 

最后终于说到is_pod了,因为使用的是MS的编译器,因此看看MSDN中的解释:

An instance of the type predicate holds true if the type Tyis 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 2008SP1的编译器来测试的,而且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; };

 

// 定义了1POD对象以及一个迭代的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