C++ Primer学习纪录(二)别名的使用、auto和decltype类型指示符

别名

定义别名有两种方法,一种是从C语言沿用下来的typedef关键词, 还有一种为C++11重新加入的using来对别名进行声明

用法

typedef double wages;
typedef wages base, *p;

typedef struct TNode {
	int data;
	struct TNode *left, *right;
} TNode, *TreeNode;

// using 的使用
using wages = double;
using TreeNode = struct TNode {
	int data;
	struct TNode *left, *right;
};

注意点

对于复合类型而言,会有一些意想不到的后果

typedef char *pstring;
char c = 'a', d = 't';
const pstring cstr_1 = &c;
const char* cstr_2 = &c;

对于上述语句,const pstring cstr_1 = &c定义了一个指向char类型的常量指针,即不能改变指针指向的值,即cstr_1 = &d 会报错;

const char* cstr_2 = &c则定义了一个指向常量的指针,即无法通过指针来对指向对象进行修改,即*cstr_2 = d 会报错, 但cstr_2 = &d 可以顺利进行。

类型说明符

非常好用的auto声明符?

C++11中引入的auto声明符允许C++编译器来帮助我们进行类别的分析,用法十分简单,但也需要注意几个点:

  1. 对于写在同一条声明语句中的代码,必须有着相同的基本数据类型。
  2. 对于const关键字而言,若用auto进行分析,则会忽略顶层const,保留底层const
    以下用具体代码说明
int a = 10;
auto b = a, *p = &a; // 正确写法,a是int类型, p是指向int类型的指针,因此为相同的基本数据类型
auto b = 3.14, *p = &a; // 错误写法, b是double类型, 而p是指向int类型的指针, 数据类型不相同

对于第二点,先回顾下顶层const和底层const, 首先顶层const和底层const只在const作用于指针时会有所区别,直接作用于目标对象时没有区别(例如const int),可以把这类对象默认为顶层const; 其次在指针中,当const限定的对象为指针时,其为顶层const;否则为底层const

const int a = 10; // 默认为顶层const
auto b = a; // b为int类型, 但auto忽略了const属性
b = 7;
cout << b; 
output: 7

const int a = 10, *p = &10; // 指向常量的指针, 为底层const
auto ptr = p; // ptr依旧是指向常量的指针,并且保留了底层const的特性
cout << *ptr;
output: 10

// 以下语句运行错误,由于ptr是指向常量的指针,不可通过ptr改变对象的值
*ptr = 20; 

// p是常量指针,const修饰指针,故为顶层const,p指向的对象不可改变
int* const p = &a; 
auto ptr = p; // p是指向int的指针 auto忽略了const 因此ptr的值可以改变
int b = 50;
ptr = &b;
cout << ptr;
output: 50

// 对于引用
int a = 10, &b = a;
auto c = b; // c为int类型

decltype类型指示符

引用书上的原话在这里插入图片描述
可能书上的描述有些隐晦,稍微解释一下。
autodecltype的区别类似constconstexpr

  1. 对于auto声明符而言, 对类型的推断是在编译时候完成的,编译器会尝试计算一次变量的值,并用这个值初始化auto所声明的对象, 例如auto a = foo(), 编译器在编译时就会把foo()的值计算出来,并赋值给变量a
  2. 对于decltype类型指示符而言,编译器并不会计算function()的值,而是分析function来推断变量类型,由于不会计算值,所以不会在编译阶段给变量赋值,该操作全部在运行时进行。

这也是为什么在有auto的前提下引入decltype类型指示符的原因,因为在编译时有时我们并不打算在编译的机器上得到这个变量的值(或者在编译机器上有各种限制,比如无法连接数据库等等)。

decltype语法

decltype(target_type) name = init_value;

其中target_type是用来推断的数据类型,可以是常量也可以是表达式/函数

const的处理上上decltypeauto的区别

前面已经提到,const对于顶层const是直接忽略的,对于底层const是保留的;而decltype则有所不同。

  1. 对于低层constdecltype依旧是保留,这一点与auto没有区别
  2. 对于顶层const和引用类型,若target_type为常量,则其保留常量中所有的限制; 若target_type不是常量,而是表达式/函数,则其丢弃所有顶层const的特性

以下通过代码说明

  1. 常量
const int a = 10, &b = a;
// a和引用b均为顶层const
decltype(a) x = 0; // x保留a的限制,等同于 const int x = 0;
x = 10; //  报错
decltype(a) y = a; // y类似于为const int y = x;
decltype(b) z = x; // z类似于 const int &z = x; z为常量引用类型

//底层const情况
const int* p = &a;
decltype(p) ptr = &a;  // ptr 保留底层const所有特性, 即p为指向常量的指针

注:上面代码中,由于z为引用类型,由于引用必须被初始化的特性,z必须被初始化。

  1. 表达式/变量
const int a = 10, &b = a;
decltype(a) x = 0; // 上述可知对x的定义等同const int x = 0;
decltype(a + 0) y = 0; // a + 0是表达式,因此y丢失了所有的顶层const情况
decltype(b + 0) z = 0; // b + 0是表达式,z丢失了引用的信息
// 与 int y = 0;  int z = 0;是一样的
y = 20; // 正确运行
  1. decltype的特殊点
    1. 对于解引用符,得到的是引用类型
    2. 对于decltype((variable)), 得到的类型是引用类型
const int a = 10, &b = a, *p = &a;
decltype(*p) c; // 错误, c是引用类型,必须初始化
decltype(*p) c = a; // 正确, c是引用类型并且初始化了

decltype(b) d; //错误, d是引用类型,必须初始化
decltype(b) d = a; // 正确, d是引用类型并且初始化了

decltype(a) e; // 没有括号时正确, e是int类型, 可以不进行初始化
decltype((a)) e; //错误, e是引用类型,必须初始化
decltype((a)) e = a; // 正确, e是引用类型并且初始化了

注:以上例子中引用类型为int&

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值