C++11|列表初始化 声明

目录

一、C++11简介

二、列表初始化

2.1{}初始化

 2.2std::initializer_list

2.2.1原理 

 2.2.2使用场景

 三、声明

3.1auto && typeid().name()

3.2decltype 


 

一、C++11简介

小故事:

1998年是C++标准委员会成立的第一年,本来计划以后每5年实际需要更新一次标准,C++国际标准委员会在研究C++ 03的下一个版本的时候,一开始计划是2007年发布,所以最初标准叫C++ 07。但是到06年的时候,官方觉得2007年坑定完不成C++ 07,而且官方觉得2008年可能也玩不成。最后干脆叫C++ 0x。x的意思是不知道到底能在07还是08还是其他年完成。结果2010年的时候也没完成,最后在11年终于完成了C++标准。所以最终定名为C++ 11。

C++11相对98/03,带来了数量可观的变化,其中包含约140新特性,以及对03标准约600个缺陷的修正,其次,11能更好地用于系统开发和库开发、语法更加范化和简单化、更加稳定和安全,不仅功能更强大、而且能提升程序员的开发效率,企业中项目开发中也用得比较多,所以需要重点学习。C++11的特性很多,只需挑重点进行学习。

二、列表初始化

2.1{}初始化

在c++98中,标准规定{}只能对数组或者结构进行初始化。

而在c++11中,{}不仅兼容98的规定,还可以对内置类型和自定义类型进行初始化,可添加等号(=),也可不添加。例子:

内置类型:

#include <iostream>using namespace std;
int main()
{int a{ 1 };int b = { 3 };cout << a << endl << b << endl;int arr[]{ 1,2,3,4,5 };int brr[] = { 32,3,5,42,1 };for (auto e : arr){cout << e;}cout << endl;for (auto e : brr){cout << e;}return 0;
}

输出结果:

自定义类型: 

#include <iostream>using namespace std;
class Date
{
public:Date(int year, int month, int day):_year(year), _month(month), _day(day){}void Print(){cout << _year << ":" << _month << ":" << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d{ 2024,6,12 };d.Print();Date d2 = { 2024,6,12 };d2.Print();return 0;
}

输出结果:

 2.2std::initializer_list

在学习过的c++98中,所谓的成员初始化赋值,走的是初始化列表, 实则最终调用的是成员的构造函数进行初始化,在C++11中,不仅可以兼容98的初始化构造,还给出了属于自己的初始化列表,该初始化列表是一个类模板,内部由两个指针维护着,还有些版本是由一个指针和一个变量维护,当然我们学习的是官方的两个指针的版本。当使用{}进行初始化时,走的就是c++11的初始化列表。

  

初始化列表支持以下操作: 

2.2.1原理 

 那么当使用{}进行初始化时具体是如何做的?

 若是两个指针的版本,使用初始化列表时编译器会生成一个临时数组来存储初始化列表中的元素,并将这个数组的起始位置和最后一个元素的下一个位置指针和大小传递给std::initializer_list的构造函数,这些步骤由编译器完成。如下:初始化列表部分源码

//初始化列表部分源码
template <class _Elem>
class initializer_list {
public:using value_type      = _Elem;using reference       = const _Elem&;using const_reference = const _Elem&;using size_type       = size_t;using iterator       = const _Elem*;using const_iterator = const _Elem*;constexpr initializer_list() noexcept : _First(nullptr), _Last(nullptr) {}constexpr initializer_list(const _Elem* _First_arg, const _Elem* _Last_arg) noexcept: _First(_First_arg), _Last(_Last_arg) {}_NODISCARD constexpr const _Elem* begin() const noexcept {return _First;}_NODISCARD constexpr const _Elem* end() const noexcept {return _Last;}_NODISCARD constexpr size_t size() const noexcept {return static_cast<size_t>(_Last - _First);}private:const _Elem* _First;const _Elem* _Last;
};

 若是一个指针,一个变量的版本,使用初始化列表时编译器会生成一个临时数组来存储初始化列表中的元素,并将这个数组的起始位置和数组的大小传递给std::initializer_list的构造函数,这些步骤由编译器完成。此外,如下:初始化列表部分源码

    template<class _E>class initializer_list{public:typedef _E 		value_type;typedef const _E& 	reference;typedef const _E& 	const_reference;typedef size_t 		size_type;typedef const _E* 	iterator;typedef const _E* 	const_iterator;private:iterator			_M_array;size_type			_M_len;// The compiler can call a private constructor.constexpr initializer_list(const_iterator __a, size_type __l): _M_array(__a), _M_len(__l) { }public:constexpr initializer_list() noexcept: _M_array(0), _M_len(0) { }// Number of elements.constexpr size_typesize() const noexcept { return _M_len; }// First element.constexpr const_iteratorbegin() const noexcept { return _M_array; }// One past the last element.constexpr const_iteratorend() const noexcept { return begin() + size(); }};template<class _Tp>constexpr const _Tp*begin(initializer_list<_Tp> __ils) noexcept{ return __ils.begin(); }template<class _Tp>constexpr const _Tp*end(initializer_list<_Tp> __ils) noexcept{ return __ils.end(); }

 2.2.2使用场景

 由于C++11初始化列表的出现,STL容器也发生了变化,有了新的初始化。如下:

在这里介绍一下vector和map的初始化列表: 

vector:

map: 

 

#include <iostream>
#include <vector>
#include <map>
using namespace std;
int main()
{vector<int> v{ 1,2,3,4 };for (auto e : v){cout << e << " ";}cout << endl;v = { 3,4,22,2,9 };for (auto e : v){cout << e << " ";}cout << endl;map<string, string> m{ {"apple","苹果"},{"banana","香蕉"},{"string","字符串"} };for (auto& e : m){cout << e.first << ":" << e.second << endl;}m = { {"I","我"},{"love","爱"},{"you","你"} };//等号可省略for (auto& e : m){cout << e.first << ":" << e.second << endl;}return 0;
}

 输出结果:

 在这里为了更好的对初始化列表有一个了解,用其来实现一下vector的初始化:

#include <initializer_list>
#include <iostream>using namespace std;namespace bit
{template<class T>class vector{public:typedef T* iterator;vector(initializer_list<T> lt){_start = new T[lt.size()];_finish = _start + lt.size();_endofstorage = _start + lt.size();iterator st = _start;typename initializer_list<T>::iterator it = lt.begin();while (it != lt.end()){*st++ = *it++;}}vector<T>& operator=(initializer_list<T> lt){vector<T> temp(lt);std::swap(_start,temp._start);std::swap(_finish, temp._finish);std::swap(_endofstorage, temp._endofstorage);return *this;}private:T* _start;T* _finish;T* _endofstorage;};}

 三、声明

c++11提供了多种简化声明的方式,尤其是在使用模板时。

3.1auto && typeid().name()

想必auto都已经很熟悉了,在前面就经常使用,在c++98中auto是一个存储类型的说明符,表明变量是局部自动存储类型,大意就是变量具有局部属性,拥有自动生命周期,但是不加该说明符,局部域中定义局部的变量默认是局部自动存储类型,拥有局部属性,拥有自动生命周期,所以在这里auto就没有啥体现价值。c++11了,就弃掉原来的用法,对其进行了翻新,将其用于实现自动类型推断,如此,定义时要求进行显示初始化,让编译器识别初始化值的类型,将定义对象的类型设置为初始化值的类型。

#include <iostream>
#include <vector>
#include <map>
using namespace std;
int main()
{int i = 3;auto p = &i;//已知&i类型,编译器根据其类型自动将变量p的类型推导为int*类型。auto pf = strcpy;//strcpy是一个函数,其也拥有返回值类型//为了能够验证他们的返回值类型,可以通过typeid,其作用获取类型名,以c-style字符串形式返回类型名//注意:对非引用类型,typeid().name()是在编译时期识别的,只有引用类型才会在运行时识别。cout << typeid(p).name() << endl;cout << typeid(pf).name() << endl;return 0;
}

输出结果:

3.2decltype 

将变量的类型声明为表达式指定的类型,可用作模板实参,定义对象。

#include <iostream>
#include <vector>
using namespace std;
int main()
{const int x = 1;double y = 2.2;decltype(x* y) ret;//定义对象,ret的类型是double类型decltype(&x) p;//p的类型是int*类型cout << typeid(ret).name() << endl;cout << typeid(p).name() << endl;vector<decltype(y)> v{ 1.1,2.2,3.3,4.4 };//用作模板参数for (auto e : v){cout << e << " ";}return 0;
}

 输出结果:

当然还有nullptr,在c++中,NULL是被当做0,而nullptr才被当做空指针((void*)0)。

end~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/41591.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AndroidKille不能用?更新apktool插件-cnblog

AndroidKiller不更新插件容易报错 找到apktool管理器 填入apktool位置&#xff0c;并输入apktool名字 选择默认的apktool版本 x掉&#xff0c;退出重启 可以看到反编译完成了

JavaDS预备知识

集合框架 Java 集合框架 Java Collection Framework &#xff0c;又被称为容器 container &#xff0c;是定义在 java.util 包下的一组接口 interfaces和其实现类 classes 。 其主要表现为将多个元素 element 置于一个单元中&#xff0c;对数据进行创建(Create)、读取(Retrieve…

【论文阅读】-- Interactive Horizon Graphs:改进多个时间序列的紧凑可视化

Interactive Horizon Graphs: Improving the Compact Visualization of Multiple Time Series 摘要1 引言2 相关工作2.1 多个时间序列的可视化2.2 缩减折线图 &#xff08;RLC&#xff09;2.3 地平线图 &#xff08;HG&#xff09;2.4 大尺度和小尺度变异数据集2.5 多个时间序列…

【Docker系列】Docker 镜像构建中的跨设备移动问题及解决方案

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【C++】 解决 C++ 语言报错:Invalid Use of ‘void’ Expression

文章目录 引言 在 C 编程中&#xff0c;错误使用 void 表达式&#xff08;Invalid Use of ‘void’ Expression&#xff09;是常见的编译错误之一。void 类型表示没有返回值&#xff0c;当程序试图将 void 类型的表达式用作有值表达式时&#xff0c;会引发此错误。本文将深入探…

Redis---8---哨兵(sentinel)

Redis—8—哨兵&#xff08;sentinel&#xff09; 是什么 吹哨人巡查监控后台master主机是否故障&#xff0c;如果故障了根据*** 投票数 *** 自动将某一个从库转换为新主库&#xff0c;继续对外服务。 作用&#xff1a; 俗称&#xff0c;无人值守运维 ​ 1&#xff0c;监控…

layui-表单(输入框)

1.基本使用方法 先写一个表单元素块 form 加上layui-form 里面写行区块结构&#xff0c;如下&#xff1a; 2.输入框选项 placeholder默认文本 autocomplete自动填充 lay-verify required必填

芯片的PPA-笔记

写在前面&#xff1a;这个仅记录自己对芯片PPA的一些思考&#xff0c;不一定正确&#xff0c;还请各位网友思辨的看待&#xff0c;欢迎大家谈谈自己的想法。 1 此次笔记的起因 记录的原因&#xff1a;自己在整理这段时间的功耗总结&#xff0c;又看到工艺对功耗的影响&#x…

Spring AOP源码篇二之 代理工厂ProxyFactory学习

了解AspectJ表达式以及PointCut、Advice、Advisor后&#xff0c;继续学习Spring AOP代理工厂 AspectJ表达式参考&#xff1a;Spring AOP之AspectJ表达式-CSDN博客 PointCut、Advice、Advisor参考&#xff1a;Spring AOP源码篇一之 PointCut、Advice、Advisor学习-CSDN博客 简单…

H5 Canvas实现转盘效果,控制指定数字

效果图 实现思路&#xff1a; 用Canvas画圆&#xff0c;然后再画扇形&#xff0c;然后中奖的开始用一张图片代替&#xff0c;点击的时候触发转动效果。 实现代码&#xff1a; <!DOCTYPE html> <html> <head><meta charset"utf-8"><tit…

MQ:RabbitMQ

同步和异步通讯 同步通讯: 需要实时响应,时效性强 耦合度高 每次增加功能都要修改两边的代码 性能下降 需要等待服务提供者的响应,如果调用链过长则每次响应时间需要等待所有调用完成 资源浪费 调用链中的每个服务在等待响应过程中,不能释放请求占用的资源,高并发场景下…

排序——交换类排序、插入类排序、选择类排序、归并类排序

排序 排序算法分为交换类排序、插入类排序、选择类排序、归并类排序。 交换类排序 冒泡排序 冒泡排序的基本思想是&#xff1a;从后往前&#xff08;或从前往后&#xff09;两两比较相邻元素的值。若A[ j - 1 ] > A[ j ]&#xff0c;则交换它们&#xff0c;直到序列比较…

commonjs、module 模块同时启动

怎样同时在一个项目中同时启动node服务和我们前端项目&#xff08;commonjs、module 模块同时启动&#xff09; 今天在使用node实现完增删改查的接口之后&#xff0c;将自己node代码嵌入到我们react项目中 启动完前端项目之后&#xff0c;当我使用node service.js的时候&#x…

Unity 简单载具路线 Waypoint 导航

前言 在游戏开发和导航系统中&#xff0c;"waypoint" 是指路径中的一个特定位置或点。它通常用于定义一个物体或角色在场景中移动的目标位置或路径的一部分。通过一系列的 waypoints&#xff0c;可以指定复杂的移动路径和行为。以下是一些 waypoint 的具体用途&…

用Python轻松转换PDF为CSV

数据的可访问性和可操作性是数据管理的核心要素。PDF格式因其跨平台兼容性和版面固定性&#xff0c;在文档分享和打印方面表现出色&#xff0c;尤其适用于报表、调查结果等数据的存储。然而&#xff0c;PDF的非结构化特性限制了其在数据分析领域的应用。相比之下&#xff0c;CS…

【国产开源可视化引擎Meta2d.js】图元

图元 又称画笔Pen。图形表达的基本元素&#xff0c;组成图像的基本单元。 构成 每一个图元由ID、名字、类型、属性&#xff08;数据&#xff09;组成。 ID 名为“id”的特殊属性&#xff0c;图元实例&#xff08;画布上的图元对象&#xff09;的唯一标识。拖拽到画布或创建…

【线性代数的本质】矩阵与线性变换

线性变化要满足两点性质&#xff1a; 直线&#xff08;连续的点&#xff09;在变换后还是直线。原点不变。 假设有坐标轴&#xff08;基底&#xff09; i ^ \widehat{i} i 和 j ^ \widehat{j} j ​&#xff1a; i ^ [ 1 0 ] , j ^ [ 0 1 ] \widehat{i}\begin{bmatrix} 1 \…

《昇思25天学习打卡营第6天|网络构建》

文章目录 前言&#xff1a;今日所学&#xff1a;1. 定义模型类2. 模型层3. 模型参数 前言&#xff1a; 在第六节中我们学习了网络构建&#xff0c;了解了神经网络模型是由神经网络层和Tensor操作构成&#xff0c;我们使用的mindspore.nn中提供了常见的升级网络层的实现&#x…

在线图片转文字的软件,分享3种强大的软件!

在信息爆炸的时代&#xff0c;图片作为信息的重要载体之一&#xff0c;其内容往往蕴含着巨大的价值。然而&#xff0c;面对海量的图片信息&#xff0c;如何高效、准确地将其转化为文字&#xff0c;成为了许多人的迫切需求。今天&#xff0c;就为大家盘点几款功能强大的在线图片…

【python基础】—如何理解安装程序时要配置Widows和DOS操作系统中的path环境变量?

文章目录 前言一、环境变量是什么&#xff1f;二、为什么需要设置环境变量&#xff1f;三、配置anaconda的环境变量 前言 在安装一些程序的时候&#xff0c; 我们总是需要将安装路径配置到正在使用电脑的环境变量里。为什么要进行这一步呢&#xff1f;本文主要解释Widows和DOS…