美文网首页C++C++2.0
C++ decltype 与 auto关键字

C++ decltype 与 auto关键字

作者: wayyyy | 来源:发表于2018-07-05 23:29 被阅读5次
顶层const 与 底层const

指针本身是不是常量 和 指针所指的是不是一个常量 是2个问题。
顶层const 表示指针本身是常量。
底层const 表示指针所指的对象是个常量。
更一般的是顶层const 表示任意对象是常量,底层const则是与指针和引用有关(使得被修饰的变量本身无法改变的const是顶层const,其他的通过指针或引用等间接途径来限制目标内容不可变的const是底层const)

int i = 0;
int *const p1 = &i;      // 不能改变p1的值(即p1只能指向i),这是一个顶层const

const int ci = 42;       // 不能改变ci的值,这是一个顶层const
const int *p2 = &ci;     // 不能改变ci的值,这是一个底层const

const int* const p3 = p2;  // 前一个是底层const,后一个是顶层const
const int &r = ci;   // 这是一个底层const

当执行对象拷贝的操作时,底层const 和 顶层const区别明显。顶层const无所谓,但当对象是底层const时,拷入可拷出的对象必须具有相同的底层const资格。

auto 关键字

编程时常常需要把表达式的值赋给变量,这就要求在声明变量的时候清楚地知道表达式的类型,为了解决这个问题,C++11 引入auto类型说明符,用它能让编译器替我们去分析表达式所属的类型。auto让编译器通过初始值来推算变量的类型。显然auto定义的变量必须有初始值

编译器推断出来的auto类型有时和初始值的类型并不完全一样,编译器会适当的改变结果类型使其更符合初始化规则。

  • 数组

    int arr[3] = {1, 2, 3};
    auto i = arr        // auto推断出的i是整型指针
    decltype(arr) arr2  // decltype 推断出的是和 arr 一样的数组类型
    
  • 引用类型
    使用引用其实是使用引用的对象,特别是当引用被用作初始值时,真正参与初始化的其实是引用对象的值,此时编译器以引用对象的类型作为auto的类型:

    int i = 0
    int &r = i;
    auto a = r;    // a是一个整数
    
  • auto 一般会忽略掉顶层const,同时底层const则会保留下来。

    const int ci = i;        // 顶层const
    const int &cr = ci;      // 底层const
    
    auto b = ci;     // b 是一个整数(ci 的顶层const特性被忽略掉了)
    auto c = cr;     // c 是一个整数 (cr 是引用)
    
    auto d = &i;     // d是int*
    auto e = &ci;    // e是const int*
    
    auto &g = ci;    // const int&
    
decltype 关键字

有时会遇到这种情况:希望从表达式的类型推断出要定义的变量类型,但是不想用该表达式的值初始化变量。为了满足这一要求,C++11标准引入了第二种类型说明符decltype,它的作用是选择并返回操作数的数据类型,在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。

decltype(f()) sum = x;  // sum的类型就是函数f的返回类型。

decltype处理顶层const 和 引用的方式 与 auto 有些许不同,如果decltype使用表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内)

const int ci = 0;
const int &cj = ci;

decltype(ci) x = 0;    // x 的类型是 const int    
decltype(cj) y = x;    // y 的类型是const int&,y 绑定到变量x
decltype(cj) z;        // 错误:z 是一个引用,必须初始化

如果decltype使用的是表达式,则decltype返回表达式结果对应的类型。

int i = 42;
int *p = &i;
int &r = i;

decltype(r) j;         // j 是引用
decltype(r+0) b;       // b是int
decltype(*p) c;        // c是int&,这里必须要初始化

r 是一个引用,则j也必须是引用。
r+0 是一个算术表达式,返回的是一个右值,所以b是int。
*p,解引用表达式返回的是左值,所以c是引用,而不是int。

另外,变量名加上一对括号,则得到的类型也会与不加括号不同,如果 decltype 使用的是一个不加括号的变 量,则得到的结果就是该变量的类型。如果给变量加上了一层或多层括号,编译器就会把它当成一个表达式,变量是一种可以赋值语句左值的特殊表达式,所以这样的decltype就会得到引用类型。

int i = 10;

decltype(i) e;      // e是一个未初始化的int 
decltype((i)) d;    // d是一个int&,这里必须要初始化
常量表达式 与 constexpr 关键字

常量表达式是指在编译期间就能计算得到值得表达式。
字面值是常量表达式。
用常量表达式初始化的const的对象也是常量表达式。

一个对象是不是常量表达式,是由它的数据类型和初始值共同决定的,例如:

const int a = 5;  // 常量表达式
const int b = a+3;    // 常量表达式
int c = 30;       // 非常量表达式,虽然初始值30是字面值,但是赋值操作需要在运行时才能进行
const int sz = get_size();  // 非常量表达式,初始值不是常量,需要在运行时确定

为了让编译器帮助验证常量表达式,C++11中引入了 constexpr关键字。如果想让一个表达式成为常量表达式,就使用 constexpr进行声明,当编译器发现声明的表达式并不是常量表达式时,就会报错,这就减少了出错的概率。

#include <iostream>

int func()  {  return 1;  }

int main()  
{
    constexpr int i = func();  // error,编译器不能计算得到Func的返回值。
}

constexpr 变量可以由特殊的constexpr函数初始化,C++11中对constexpr函数的形式有严格的要求:其函数体只能含有一条return 语句,并且return 语句只能含有字面值类型或其他的constexpr函数。

#include <iostream>
#include <string>

int F1()  {  return 1;  }
constexpr int F2(int n)  {  return 5;  }    // OK
constexpr int F3(int n)  {  const expr int i = 5;  return 5;  }  // 
constexpr int F4(int n)  {  return F1();  }  // 错误,返回非字面值类型

参考资料
1. Stanley B. Lippman, Barbara E. Moo. C++ primer[M]. 电子工业出版社,2013
2. https://zhuanlan.zhihu.com/p/39307289

相关文章

  • C++ decltype 与 auto关键字

    顶层const 与 底层const 指针本身是不是常量 和 指针所指的是不是一个常量 是2个问题。顶层const ...

  • C++11中auto和decltype

    C++11中auto和decltype auto和decltype都是C++11中引进来用于自动推断类型的关键字,...

  • C++11拾穗

    C++11新关键字 alignas:指定对齐大小 alignof:获取对齐大小 decltype auto(重新定...

  • C++11的新特性

    1、统一的初始化方法 2、auto关键字 3、decltype关键字 4、智能指针 sheared_ptr 5、n...

  • C/C++关键字介绍

    一、 typedef typedef为C/C++的关键字,与auto、extern、mutable、static、...

  • auto && decltype

    auto:C++11标准引入的类型说明符,编译器通过初始值来推算变量的类型。因此,auto定义的变量必须有初始值a...

  • auto & decltype

    使用auto和decltype来实现实参推断时,遇到下面case: 执行结果为: 如果把sum中的注释的cout打...

  • [C++11阅读][3-3-1]RTTI机制与typeid

    本篇是番外篇,介于auto和decltype之间,讲的是C++对RTTI的支持,既有C++98的函数,也有C++1...

  • 【Swift 3 && C++11】<第一

    | Swift | C++:-:|:-:|:-:关键字 | let / var | const auto / au...

  • c++第一讲

    目标 c++关键字 命名空间 c++输入和输出 缺省参数 函数重载 引用 内联 auto关键字 基于范围的for循...

网友评论

    本文标题:C++ decltype 与 auto关键字

    本文链接:https://www.haomeiwen.com/subject/eohuuftx.html