C++11的decltype关键字

获取表达式的类型

        auto用于通过一个表达式在编译时确定待定义的变量类型,auto所修饰的变量必须被初始化,编译器需要通过初始化来确定auto所代表的类型,即必须要定义变量。若仅希望得到类型,而不需要(或不能)定义变量的时候就要使用C++11新增的decltype关键字了,用于在编译时推导出一个表达式的类型。它的语法格式如下:

        decltype (exp)

        其中,exp表示一个表达式。

        从格式上来看,decltype很像sizeof---用来推导表达式类型大小的操作。类似于sizeof,decltype的推导过程是在编译期完成的,并且不会真正计算表达式的值。 

       int x = 0;      

        decltype (x) y = 1;                // y -> int

        decltype (x + y) z = 0;          // z -> int

        const int& i = x;                    

        decltype (i) j = y;                  // j -> const int &

        const decltype (z) * p = &z;  // *p -> const int, p -> const int *

        decltype (z) * pi = &z;           // *pi -> int,pi -> int*

        decltype (pi) * pp = π        // *pp -> int*,pp -> int **

        y和z的结果表明decltype可以根据表达式直接推导出它的类型本身。

        j的结果表明decltype通过表达式得到的类型,可以保留住表达式的引用以及const限定符。实际上,对于一般的标记符表达式,decltype将精确的推导出表达式定义本身的类型,不会像auto那样在某些情况下舍弃引用和cv限定符。

        p,pi的结果表明decltype可以像auto一样,加上引用和指针,以及cv限定符。

        pp的推导则表明,当表达式是一个指针的时候,decltype仍然推导出表达式的实际类型(指针类型),之后结合pp定义的指针标记,得到的pp是一个二维指针类型。

decltype的推导规则

        介绍decltype(exp)的推导规则:

        推导规则1:exp是标识符,类访问表达式,decltype(exp)和exp的类型一致。

        推导规则2:exp是函数调用,decltype(exp)和返回值的类型一致。

        推导规则3:其他情况,若exp是一个左值,则decltype(exp)是exp类型的左值引用,否则和exp类型一致。

        为了更好的讲解这些规则的使用场景,下面根据上面的规范分3种情况一次讨论:

        1、标识符表达式和类访问表达式。

        2、函数调用(非标识符表达式,也非类访问表达式)。

        3、带括号的表达式和加法运算表达是否(其他情况)。

标识符表达式和类访问表达式示例:     

  class Foo

        {

                public static const int Number = 0;

                int x;

        };

        int n = 0;

        volatile const int& x = 0;

        decltype(n) a = n;                //a -> int

        decltype(x) b = n;                //b -> volatile const int &

        decltype(Foo::Number) c = 0;        // c -> const int 

        Foo foo;

        decltype(foo.x) d = 0;            // d -> int,类访问表达式

        变量a,b,c保留了表达式的所有属性(cv,引用)。这里的结果是很简单的,按照推导规则1,对于标识符表达式而言,decltype的推导结果就和这个变量的类型定义一致。

        d是一个类访问表达式,也符合推导规则1。

函数调用示例:

        int & func_int_r();        //左值(可简单理解为可寻址值)

        int func_int();               //纯右值

        const int& func_cint_r();        //左值

        const int func_cint();        //纯右值

        const Foo func_cfoo();        //纯右值



        int x = 0;

        decltype (func_int_r()) a1 = x;        //a1 -> int &

        decltype(func_int()) c1 = 0;             // c1 -> int 

        decltype (func_cint_r()) a1 = x;        //a1 -> const int &

        decltype(func_cint()) c1 = 0;             // c1 -> int 

        decltype(func_cfoo()) ff = Foo;        //ff -> const Foo

        可以看到,按照推导规则2,decltype的结果和函数的返回值类型保持一致。

   

带括号的表达式和加法运算表达式示例:

        struct Foo {int x;};     

        const Foo foo = Foo();

        decltype(foo.x) a = 0;                // a -> int

        decltype((foo.x));                       // b -> const int &

        int n = 0, m = 0;

        decltype(n + m) c = 0;                // c -> int

        decltype(n += m) d = c;                // d -> int&

        a和b的结果:仅仅多了一对括号,它们得到的类型却是不同的。

        a的结果很直接的,根据推导规则1,a的类型就是foo.x的定义类型。

        b的结果并不适用于推导规则1和2.根据foo.x是一个左值,可知括号表达式也是一个左值。因此可以按照推导规则3,知道decltype的结果将是一个左值引用。

        foo的定义是const Foo,所以foo.x是一个const int类型左值,因此decltype的推导结果是const int&.

        同样,n+m返回一个右值,按照推导规则3,decltype的结果为int。

        最后,n + m返回一个左值,按照推导规则3,decltype的结果为int &。

        

你可能感兴趣的:(C++11,c++,开发语言)