C++各个版本新增对于算法有用特性
C++11
auto与decltype类型推导(摘自程序喵大人)
auto
auto可以让编译器在编译器就推导出变量的类型,话不多说上代码:
auto a = 10; // 10是int型,可以自动推导出a是int
int i = 10;auto b = i; // b是int型
auto d = 2.0; // d是double型
这就是auto的基本用法,可以通过=右边的类型推导出变量的类型。
<font size=3auto推导规则
直接看代码
代码1:
int i = 10;auto a = i, &b = i, *c = &i; // a是int,b是i的引用,c是i的指针,auto就相当于intauto d = 0, f = 1.0; // error,0和1.0类型不同,对于编译器有二义性,没法推导auto e; // error,使用auto必须马上初始化,否则无法推导类型
代码2:
void func(auto value) {} // error,auto不能用作函数参数
class A { auto a = 1; // error,在类中auto不能用作非静态成员变量 static auto b = 1; // error,这里与auto无关,正常static int b = 1也不可以 static const auto int c = 1; // ok};
void func2() { int a[10] = {0}; auto b = a; // ok auto c[10] = a; // error,auto不能定义数组,可以定义指针 vector<int> d; vector<auto> f = d; // error,auto无法推导出模板参数}
auto的限制:
- auto的使用必须马上初始化,否则无法推导出类型
- auto在一行定义多个变量时,各个变量的推导不能产生二义性,否则编译失败
- auto不能用作函数参数
- 在类中auto不能用作非静态成员变量
- auto不能定义数组,可以定义指针
- auto无法推导出模板参数
再看这段代码:
int i = 0;auto *a = &i; // a是int*auto &b = i; // b是int&auto c = b; // c是int,忽略了引用
const auto d = i; // d是const intauto e = d; // e是int
const auto& f = e; // f是const int&auto &g = f; // g是const int&
首先,介绍下,这里的cv是指const 和volatile
推导规则
- 在不声明为引用或指针时,auto会忽略等号右边的引用类型和cv限定
- 在声明为引用或者指针时,auto会保留等号右边的引用和cv属性
decltype
上面介绍auto用于推导变量类型,而decltype则用于推导表达式类型,这里只用于编译器分析表达式的类型,表达式实际不会进行运算,上代码:
int func() { return 0; }decltype(func()) i; // i为int类型
int x = 0;decltype(x) y; // y是int类型decltype(x + y) z; // z是int类型
注意:decltype不会像auto一样忽略引用和cv属性,decltype会保留表达式的引用和cv属性
cont int &i = 1;int a = 2;decltype(i) b = 2; // b是const int&
decltype推导规则
对于decltype(exp)有
- exp是表达式,decltype(exp)和exp类型相同
- exp是函数调用,decltype(exp)和函数返回值类型相同
- 其它情况,若exp是左值,decltype(exp)是exp类型的左值引用
int a = 0, b = 0;decltype(a + b) c = 0; // c是int,因为(a+b)返回一个右值decltype(a += b) d = c;// d是int&,因为(a+=b)返回一个左值
d = 20;cout << "c " << c << endl; // 输出c 20
auto和decltype的配合使用
auto和decltype一般配合使用在推导函数返回值的类型问题上。
下面这段代码
template<typename T, typename U>return_value add(T t, U u) { // t和v类型不确定,无法推导出return_value类型 return t + u;}
上面代码由于t和u类型不确定,那如何推导出返回值类型呢,我们可能会想到这种
template<typename T, typename U>decltype(t + u) add(T t, U u) { // t和u尚未定义 return t + u;}
这段代码在C++11上是编译不过的,因为在decltype(t +u)推导时,t和u尚未定义,就会编译出错,所以有了下面的叫做返回类型后置的配合使用方法:
template<typename T, typename U>auto add(T t, U u) -> decltype(t + u) { return t + u;}
返回值后置类型语法就是为了解决函数返回值类型依赖于参数但却难以确定返回值类型的问题。
std::array
提要
数组,在越界访问时抛出异常,建议使用std::array
替代普通的数组
在声明时需要提供数据类型及元素个数(常量)
example
std::array<int,10> a
或者constexpr int n=10; std::array<int,n> a
std::tuple
提要
元组类型,与pair相似
example
// 1.初始化列表
tuple<int, double, string> t1(1, 13.1, "wdnmd");
// 2.使用 tuple 头文件中辅助函数 make_tuple() 生成tuple 对象
tuple<int, float, char> t2 = make_tuple(2, 15.6f, 'a');
// 3.花括号推导类型初始化(since C++17)
tuple t{1, 2ll, "wdnmd", 'c'};
// 4.使用std::get<lth>(obj)来获取tuple内的值
cout << std::get<0>(t1) << ' ' << std::get<1>(t1) << ' ' << std::get<2>(t1) << endl;
// 5.得到元素个数
// 1. std::tuple_size< >::value (since C++11)
// 2. std::tuple_size_v< > (since C++17)
cout << std::tuple_size<decltype(t1)>::value << ' ' << std::tuple_size_v<decltype(t1)> << endl;
// 6.得到元素类型
// 1.std::tuple_element<1, decltype(t1)>::type (since C++11)
// 2.std::tuple_element_t<1, decltype(t1)> (since C++17)
// 3.auto (since C++11)
std::tuple_element<1, decltype(t1)>::type a = std::get<1>(t1);
std::tuple_element_t<1, decltype(t1)> b = std::get<1>(t1);
auto c = get<1>(t1);
std::unordered_set与std::unordered_map
提要
基于hash表实现的set和map,内部不会排序,使用方法与set和map类似
由于内部不是有序的所以无lowerbound等函数
一些算法
提要
- all_of:检测表达式是否对范围[first, last)中所有元素都返回true,如果都满足,则返回true
- any_of:检测表达式是否对范围[first, last)中至少一个元素返回true,如果满足,则返回true,否则返回false
- none_of:检测表达式是否对范围[first, last)中所有元素都不返回true,如果都不满足,则返回true,否则返回false
- find_if_not和find_if:返回第一个不符合要求 / 符合要求的元素迭代器
- copy_if:复制满足条件的元素
- iota:对容器内的元素按序递增赋值
- min_element和max_element:返回容器内最大元素和最小元素迭代器
- is_sorted:检测容器内是否已经排好序(默认升序),如果是,则返回true,否则返回false
- is_sorted_unitl:返回第一个不满足规定序(默认升序)的元素的迭代器
example
vector<int> a(6);
iota(a.begin(), a.end(), 2); //对a内元素从2赋值 (2,3,4,5,6,7)
//检测a内元素是否均为奇数 (输出false)
cout << all_of(a.begin(), a.end(), [](const int& i) { return i % 2; }) << endl;
//检测a内元素是否有一个为奇数 (输出true)
cout << any_of(a.begin(), a.end(), [](const int& i) { return i % 2; }) << endl;
//检测a内元素是否均不为为奇数 (输出false)
cout << none_of(a.begin(), a.end(), [](const int& i) { return i % 2; }) << endl;
//返回第一个不符合要求的元素迭代器 (输出2)
cout << *find_if_not(a.begin(), a.end(), [](const int& i) { return i % 2; }) << endl;
//返回第一个符合要求的元素迭代器 (输出3)
cout << *find_if(a.begin(), a.end(), [](const int& i) { return i % 2; }) << endl;
//返回容器内最大的元素的迭代器 (输出7)
cout << *max_element(a.begin(), a.end()) << endl;
//返回容器内最小的元素的迭代器 (输出2)
cout << *max_element(a.begin(), a.end()) << endl;
//检测容器内是否已经排好序(默认升序)
/*(输出true)*/ cout << is_sorted(a.begin(), a.end()) << endl;
/*(输出false)*/ cout << is_sorted(a.begin(), a.end(), [](const int& a, const int& b) { return a > b; }) << endl;
//返回第一个不满足规定序(默认升序)的元素的迭代器 (返回a.end()迭代器)
is_sorted_until(a.begin(), a.end());
C++14
对auto类型推导进行了优化
lambda可以像模板那样使用了
auto f = [] (auto a) { return a; };
cout << f(1) << ' '<< f(2.3f) << endl;
二进制字面量及分隔符
C++14引入了二进制字面量,也引入了分隔符,防止看起来眼花
int a = 0b11; // a = 3
double b = 3.14'1234'1234'1234;
参考链接
一文吃透C++11中auto和decltype知识点 (程序喵大人)
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/282919.html