• C++11 decltype


    【1】typeid与decltype

    C++98对动态类型支持就是C++中的运行时类型识别(RTTI)。

    (1)typeid

    RTTI的机制是为每个类型产生一个type_info类型的数据,可以在程序中使用typeid随时查询一个变量的类型,typeid就会返回变量相应的type_info数据。

    type_info的name成员函数可以返回类型的名字。

    而在C++11中,又增加了hash_code这个成员函数,返回该类型唯一的哈希值,以供程序员对变量的类型随时进行比较。应用示例如下:

     1 #include <iostream> 
     2 #include <typeinfo>
     3 using namespace std;
     4 
     5 class White {};
     6 class Black {};
     7 
     8 int main()
     9 {
    10     White a;
    11     Black b;
    12     cout << typeid(a).name() << endl; // class White
    13     cout << typeid(b).name() << endl; // class Black
    14     White c; 
    15     bool a_b_sametype = (typeid(a).hash_code() == typeid(b).hash_code());
    16     bool a_c_sametype = (typeid(a).hash_code() == typeid(c).hash_code()); 
    17     cout << "Same type? " << endl;
    18     cout << "A and B? " << (int)a_b_sametype << endl; // 0
    19     cout << "A and C? " << (int)a_c_sametype << endl; // 1
    20     system("pause");
    21 }
    22 
    23 /*运行结果
    24 class White
    25 class Black
    26 Same type?
    27 A and B? 0
    28 A and C? 1
    29 */

    值得注意一点:相比于is_same模板函数的成员类型value在编译时得到信息,hash_code是运行时得到的信息。

    (2)decltype

    与auto类似地,decltype也能进行类型推导。下面分析两者的异同:

    [1] decltype与auto的不同点

    使用方式有一定的区别。示例如下:

     1 #include <typeinfo>
     2 #include <iostream>
     3 using namespace std;
     4 
     5 int main()
     6 {
     7     int i;
     8     decltype(i) j = 0;
     9     cout << typeid(j).name() << endl; // int
    10     float a;
    11     double b;
    12     decltype(a + b) c;
    13     cout << typeid(c).name() << endl; // double
    14 }
    15 
    16 /*运行结果
    17 int
    18 double
    19 */

    看到变量j的类型由decltype(i)进行声明,表示j的类型跟i相同(或者准确地说,跟i这个表达式返回的类型相同)。

    而c的类型则跟(a+b)这个表达式返回的类型相同。由于a+b加法表达式返回的类型为double(a会被扩展为double类型与b相加),所以c的类型被decltype推导为double。

    从这个例子中可以看到,decltype的类型推导并不是像auto一样是从变量声明的初始化表达式获得变量的类型,decltype总是以一个普通的表达式为参数,返回该表达式的类型。

    [2] decltype与auto的相同点

    2.1 作为一个类型指示符,decltype也可以将获得的类型来定义另外一个变量。

    2.2 decltype类型推导也是在编译时进行的。

    【2】decltype的应用

    在C++11中,使用decltype推导类型是非常常见。

    (1)decltype与typdef/using的合用。示例如下:

    1 using size_t = decltype(sizeof(0));
    2 using ptrdiff_t = decltype((int*)0 - (int*)0);
    3 using nullptr_t = decltype(nullptr);

     (2)decltype在某些场景下,可以极大地增加代码的可读性。示例如下:

     1 #include <vector>
     2 using namespace std;
     3 
     4 int main() 
     5 {
     6     vector<int> vec;
     7     typedef decltype(vec.begin()) vectype;
     8     for (vectype i = vec.begin(); i < vec.end(); ++i) 
     9     { 
    10         // TODO...
    11     } 
    12     for (decltype(vec)::iterator i = vec. begin(); i < vec. end(); ++i)
    13     { 
    14         // TODO...
    15     } 
    16 }

     (3)重用匿名类型的利器。示例如下:

     1 enum {K1, K2, K3 } anon_e; // 匿名的枚举
     2 
     3 union
     4 { 
     5     decltype(anon_e) key; 
     6     char* name;
     7 } anon_u; // 匿名的union联合体
     8 
     9 struct 
    10 { 
    11     int d; 
    12     decltype(anon_u) id;
    13 } anon_s[100];  // 匿名的struct数组
    14 
    15 int main() 
    16 {
    17     decltype(anon_s) as;
    18     as[0].id.key = decltype(anon_e)::K1; // 引用匿名类型枚举中的值
    19 }

    (4)扩大模板泛型的能力。示例如下:

     1 template <typename T1, typename T2>
     2 void Sum(T1& t1, T2& t2, decltype(t1 + t2)& s)
     3 {
     4     s = t1 + t2; 
     5 } 
     6 
     7 int main()
     8 {
     9     int a = 3;
    10     long b = 5;
    11     float c = 1.0f, d = 2.3f;
    12     long e;
    13     float f;
    14     Sum(a, b, e);  // s的类型被推导为long
    15     Sum(c, d, f);  // s的类型被推导为float
    16 }

    (5)实例化模板。示例如下:

     1 #include <map>
     2 using namespace std;
     3 
     4 int getHash(char*);
     5 
     6 map<char*, decltype(getHash)> dict_key;             // 编译失败
     7 map<char*, decltype(getHash(nullptr)) > dict_key1;  // 编译成功
     8 
     9 double getValue(int* p = nullptr);
    10 map<int*, decltype(getValue())> dict_key3;          // 编译成功

    (6)在标准库中的一些应用。示例如下:

    1 #include <type_traits>
    2 using namespace std;
    3 
    4 typedef double (*func)();
    5 
    6 int main()
    7 { 
    8     result_of<func()>::type f;  // 由func()推导其结果类型
    9 }

    【3】decltype推导规则

    约定decltype(e)

    (1)e没有带括号则推导原类型

    [1] 写法decltype(e)

    [2] 注意当e为表达式(函数)时,其函数不能重载,否则编译失败

    (2)e带括号时推导规则

    [1] 写法decltype((e))

    [2] 推导如下:

    若参数是任何其他类型为T的表达式,且

    2.1 若e的值为将亡值,则decltype结果为T&&

    2.2 若e的值为左值,则decltype结果为T&

    2.3 若e的值为纯右值,则decltype结果为T

    示例如下:

     1 #include <iostream>
     2 #include <typeinfo>
     3 using namespace std;
     4 
     5 class CTest
     6 {
     7 public:
     8     int m_nNo;
     9 };
    10 
    11 void overloadfunc(int)
    12 {}
    13 
    14 void overloadfunc(char)
    15 {}
    16 
    17 int&& rfvalue();
    18 
    19 const bool func()
    20 {
    21     return true;
    22 }
    23 
    24 int main()
    25 {
    26     int itest = 3;
    27     int arr[3] = { 0 };
    28     int* pInt = arr;
    29 
    30     // 不带括号
    31     decltype(itest) ditest; // int
    32     decltype(arr) darr;     // int [3]
    33     decltype(pInt) dpInt;   // int *
    34 
    35     CTest clTest;
    36     decltype(clTest.m_nNo) dClTestNo; // int
    37 
    38     //decltype(overloadfunc);      // 编译不通过
    39 
    40     // 带括号 规则1 将亡值
    41     decltype(rfvalue()) r_value_f = 100;    // 将亡值 int &&
    42 
    43     // 带括号 规则2
    44     decltype(true ? itest : itest) ditest1 = itest;    // int & 三目运算符,这里返回一个左值
    45 
    46     decltype((itest)) ditest2 = itest;      // int&  返回左值
    47 
    48     decltype((++itest)) ditest3 = itest;    // int&  返回左值
    49 
    50     decltype(arr[1]) darr1 = itest;         // int&  []操作返回左值
    51 
    52     decltype(*pInt) dpInt1 = itest;         // int&  *操作返回左值
    53 
    54     decltype("hello") dstr = "world";       // const char(&)[6]  字符串字面常量为左值
    55 
    56     // 带括号 规则3
    57     decltype(12) dNum = 100;                // int
    58     decltype(itest++) dNum1 = 0;            // int   itest++返回右值
    59     decltype(func()) dFunc;                 // const bool  推导为bool
    60 }

    自行仔细分析。 

    【4】cv限制符的继承与冗余的符号

    (1)与auto不同点:auto类型推导时不能“带走”cv限制符不同。decltype是能够“带走”表达式的cv限制符的。

    但是,如果对象的定义中有const或volatile限制符,使用decltype进行推导时,其成员变量不会继承const或volatile限制符。

    示例如下:

     1 #include <type_traits>
     2 #include <iostream>
     3 using namespace std; 
     4 
     5 const int ic = 0; 
     6 volatile int iv; 
     7 struct S { int i; }; 
     8 const S a = {0}; 
     9 volatile S b;
    10 volatile S* p = &b; 
    11 const int func(int);
    12 
    13 int main() 
    14 { 
    15     cout << is_const<decltype(ic)>::value << endl;      // 1 
    16     cout << is_volatile<decltype(iv)>::value << endl;   // 1 
    17     cout << is_const<decltype(a)>::value << endl;       // 1 
    18     cout << is_volatile<decltype(b)>::value << endl;    // 1 
    19     cout << is_const<decltype(a.i)>::value << endl;     // 0, 成员变量i不是const 
    20     cout << is_volatile<decltype(p->i)>::value << endl; // 0, 成员变量i不是volatile 
    21 
    22     decltype(func(1)) bvar;
    23     cout << is_const<decltype(func(1))>::value << endl; // 0 没有带走const
    24 }

    (2)与auto相同点:decltype从表达式推导出类型后,进行类型定义时,也会允许一些冗余的符号,比如cv限制符以及引用符号&。

    但是,通常情况下,如果推导出的类型已经有了这些属性,冗余的符号则会被忽略。

    示例如下:

     1 #include <type_traits>
     2 #include <iostream>
     3 using namespace std;
     4 
     5 int i = 1;
     6 int& j = i;
     7 int* p = &i;
     8 const int k = 1;
     9 
    10 int main()
    11 {
    12     decltype(i)& var1 = i;
    13     decltype(j)& var2 = i;  // 冗余的&, 被忽略 
    14     cout << is_lvalue_reference<decltype(var1)>::value << endl;  // 1, 左值引用
    15     cout << is_rvalue_reference<decltype(var2)>::value << endl;  // 0, 不是右值引用
    16     cout << is_lvalue_reference<decltype(var2)>::value << endl;  // 1, 是左值引用
    17 //    decltype(p)* var3 = &i;  // 无法通过编译
    18     decltype(p)* var3 = &p;  // var3的类型是int ** 
    19     auto* v3 = p;   // v3的类型是int*(注意与decltype的区别)
    20     v3 = &i;
    21 }

    good good study, day day up.

    顺序 选择 循环 总结

  • 相关阅读:
    DEDE调用当前文档中TAG标签利于内页优化提高收录量
    DEDE搜索结果将按点击排序展现方式的修改方法
    win 03 系统 IIS无法解析PHP之解决办法
    【原创】广告调用类,支持Flash调用
    中英文语言转换类
    PHP 获取内网用户MAC地址(WINDOWS/linux)解决方案
    DEDE删除文章怎么同时也删除附件,DEDE删除文章同时删除附件
    windows 2003下配置php环境
    When is a Test not a Unit Test?
    IBM WebSphere Commerce Front_dev
  • 原文地址:https://www.cnblogs.com/Braveliu/p/12244334.html
Copyright © 2020-2023  润新知