W...Y的主页 😊
代码仓库分享💕
目录
1. C++11简介
2. 统一的列表初始化
2.1 {}初始化
2.2 std::initializer_list
3. 声明
3.1 auto
3.2 decltype
4.STL中一些变化
1. C++11简介
在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了
C++98称为C++11之前的最新C++标准名称。不过由于C++03(TC1)主要是对C++98标准中的漏洞
进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。
从C++0x到C++11,C++标准10年磨一剑,第二个真正意义上的标准珊珊来迟。相比于
C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中
约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。相比较而言,
C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更
强大,而且能提升程序员的开发效率,公司实际项目开发中也用得比较多,所以我们要作为一个
重点去学习。C++11增加的语法特性非常篇幅非常多,我们这里没办法一 一讲解,所以次主要讲解实际中比较实用的语法。
C++11内容https://en.cppreference.com/w/cpp/11
2. 统一的列表初始化
2.1 {}初始化
在C++98中,标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。比如:
struct Point
{
int _x;
int _y;
};
int main()
{
int array1[] = { 1, 2, 3, 4, 5 };
int array2[5] = { 0 };
Point p = { 1, 2 };
return 0;
}
C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自
定义的类型,使用初始化列表时,可添加等号(=),也可不添加。
struct Point
{
int _x;
int _y;
};
int main()
{
int x1 = 1;
int x2{ 2 };
int array1[]{ 1, 2, 3, 4, 5 };
int array2[5]{ 0 };
Point p{ 1, 2 };
// C++11中列表初始化也可以适用于new表达式中
int* pa = new int[4]{ 0 };
return 0;
}
创建对象时也可以使用列表初始化方式调用构造函数初始化
class Date
{
public:
Date(int year, int month, int day)
:_year(year)
,_month(month)
,_day(day)
{
cout << "Date(int year, int month, int day)" << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2022, 1, 1); // old style
// C++11支持的列表初始化,这里会调用构造函数初始化
Date d2{ 2022, 1, 2 };
Date d3 = { 2022, 1, 3 };
return 0;
}
2.2 std::initializer_list
std::initializer_list的介绍文档:
initializerLlist文档http://www.cplusplus.com/reference/initializer_list/initializer_list/ std::initializer_list是什么类型:
int main()
{
// the type of il is an initializer_list
auto il = { 10, 20, 30 };
cout << typeid(il).name() << endl;
return 0;
}
initializer_list是C++11新增内容,其是一个模板对应的auto会识别大括号中的数据类型,做出相应的转变。
std::initializer_list使用场景:
std::initializer_list一般是作为构造函数的参数,C++11对STL中的不少容器就增加
std::initializer_list作为参数的构造函数,这样初始化容器对象就更方便了。也可以作为operator=的参数,这样就可以用大括号赋值。
int main()
{
vector<int> v = { 1,2,3,4 };
list<int> lt = { 1,2 };
// 这里{"sort", "排序"}会先初始化构造一个pair对象
map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} };
// 使用大括号对容器赋值
v = {10, 20, 30};
return 0;
但是这里容器使用的大括号赋值与刚才讲的{}初始化的原理是不一样的。容器的赋值是C++11新增的 initializer_list,STL容器中提供这样的initializer_list的构造接口。而我们使用的{}进行结构体的初始化是多参数的隐式类型转换。
list文档 vector文档 map文档 这些STL容器中都支持initializer_list构造。
3. 声明
C++11提供了多种简化声明的方式,尤其是在使用模板时。
3.1 auto
在C++98中auto是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局
部的变量默认就是自动存储类型,所以auto就没什么价值了。C++11中废弃auto原来的用法,将
其用于实现自动类型腿断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初
始化值的类型。
int main()
{
int i = 10;
auto p = &i;
auto pf = strcpy;
cout << typeid(p).name() << endl;
cout << typeid(pf).name() << endl;
map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} };
//map<string, string>::iterator it = dict.begin();
auto it = dict.begin();
return 0;
}
3.2 decltype
关键字decltype将变量的类型声明为表达式指定的类型。
`decltype`是C++11中引入的一个类型特征,用于确定表达式的类型。
1. 类型推断:`decltype`用于自动推断表达式的类型,而不需要显式地指定类型。
2. 模板编程:在模板元编程中,`decltype`常用于根据模板参数的类型来推导返回类型。
3. 函数签名:`decltype`可以用来声明函数,其中函数的返回类型由函数体中的返回语句确定。
4. lambda表达式:在使用lambda表达式时,`decltype`可以用来推断lambda的捕获类型。
5. 智能指针:在使用智能指针(如`std::unique_ptr`、`std::shared_ptr`)时,`decltype`可以用来获取智能指针所指向的类型。
6. 类型安全:`decltype`提供了一种类型安全的方式来处理类型,确保代码中使用的类型与预期一致。
7. 避免类型转换:`decltype`可以避免不必要的类型转换,因为它直接使用表达式的静态类型。
8. 与auto结合使用:`decltype`经常与`auto`关键字结合使用,`auto`用于变量声明,而`decltype`用于类型推断。
9. 类型特征:`decltype`可以与类型特征(如`std::is_same`)结合使用,进行编译时的类型检查。
10. 避免类型别名:在某些情况下,`decltype`可以用来避免创建冗余的类型别名。
`decltype`的引入提高了C++代码的灵活性和表达能力,特别是在模板编程和类型推断方面。
template<class T1, class T2>
void F(T1 t1, T2 t2)
{
decltype(t1 * t2) ret;
cout << typeid(ret).name() << endl;
}
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;
F(1, 'a');
return 0;
}
C++中的auto
和decltype
都是用于类型推断的关键字,但它们的用途和行为有所不同:
auto
关键字:
auto
用于声明变量时自动推断其类型。- 它基于变量的初始化表达式来确定类型。
- 在模板元编程中,
auto
通常用于从模板参数中推断类型。- 当使用
auto
声明变量时,如果初始化表达式是一个复杂类型,auto
会推断出该复杂类型。
decltype
关键字:
decltype
用于获取一个表达式的类型,而不管表达式是否有值。- 它不会对表达式求值,只关注表达式的类型。
decltype
常用于获取函数返回类型或对象类型,特别是当这些类型依赖于模板参数时。- 如果
decltype
用于未命名的右值,它会推断出对应的引用类型,例如decltype(表达式)
会推断出表达式
的引用类型。类型推断差异:
auto
在声明时会进行类型推断,如果初始化表达式是一个类型别名或decltype
表达式,auto
将推断出实际的类型。decltype
总是推断出表达式的确切类型,包括引用和const限定符。使用场景:
auto
通常用于简化模板代码的编写,尤其是在类型很长或复杂时。decltype
常用于需要精确知道表达式类型的情况,例如在编写需要返回与函数签名相同类型的模板代码时。类型别名:
auto
可以用于声明类型别名,但实际类型会在声明时被推断出来。decltype
不会创建类型别名,它只是提供了一种获取现有类型的方式。函数返回类型:
- 使用
auto
声明函数时,函数的返回类型将由函数体中的返回语句来确定。- 使用
decltype
声明函数时,返回类型将直接是函数签名中指定的类型。
总结来说,auto
和decltype
都用于类型推断,但auto
更侧重于简化代码和自动推断类型,而decltype
则提供了一种获取表达式确切类型的机制。
4.STL中一些变化
新容器
用橘色圈起来是C++11中的一些几个新容器,但是实际最有用的是unordered_map和
unordered_set。这两个我们前面已经进行了非常详细的讲解,其他的大家了解一下即可。
容器中的一些新方法
如果我们再细细去看会发现基本每个容器中都增加了一些C++11的方法,但是其实很多都是用得
比较少的。
比如提供了cbegin和cend方法返回const迭代器等等,但是实际意义不大,因为begin和end也是
可以返回const迭代器的,这些都是属于锦上添花的操作。
实际上C++11更新后,容器中增加的新方法最后用的插入接口函数的右值引用版本
但是这些接口到底意义在哪?网上都说他们能提高效率,他们是如何提高效率的? 欲知后事如何请看下一篇博客解说。
以上就是本次全部内容,感谢大家观看。