1 std::function
C++11 std::function 是一种通用、多态的函数封装,它的实例可以对任何可以调用的目标实体进行存储、复制和调用操作,它也是对 C 中现有的可调用实体的一种类型安全的包裹(相对来说,函数指针的调⽤不是类型安全的),换句话说,就是函数的容器。当我们有了函数的容器之后便能够更加方便的将函数、函数指针作为对象进行处理。
example_9 code
#include <iostream>#include <functional> //必须头文件int foo(int a){return a;}int main(){std::function<int(int)> func = foo; //包装了一个返回值为int,参数为int的函数int important = 10;std::function<int(int)> func2 = [&](int value)->int{return 1 + value + important;};std::cout<<func(10)<<std::endl;std::cout<<func2(10)<<std::endl;}
2 std::array
std::array 保存在栈内存中,相比堆内存中的 std::vector,我们就能够灵活的访问这里面的元素,从而获得更好的性能。使用std::array能够让代码变得更加现代,且封装了一些操作函数,同时还能够友好的使用标准库中的容器算法等等,比如 std::sort。
语法格式:
std::array<int, 4> arr{1, 2, 3, 4}; //固定大小,不能隐式转为指针// C风格接口传参// foo (arr , arr . size ()); // 非 法 , 无 法 隐 式 转 换foo(&arr[0], arr.size()); //显示转换为指针foo(arr.data(), arr.size()); //显示转换为指针// 使用std::sortstd::sort(arr.begin(), arr.end());
3 std::tuple
关于元组的使用有三个核心的函数:
- std::make_tuple: 构造元组
- std::get: 获得元组某个位置的值
- std::tie: 元组拆包
例子example_11 code:
#include <iostream>#include <tuple>#include <string>int main(){auto t = std::make_tuple(3.8, "A", "Barret Ren");//get获取元素std::cout<<std::get<0>(t)<<std::endl;std::cout<<std::get<1>(t)<<std::endl;std::cout<<std::get<2>(t)<<std::endl;//tie进行拆包double a;std::string b;std::string c;std::tie(a, b, c)=t;std::cout<<c<<std::endl;}
std::tuple 虽然有效,但是标准库提供的功能有限,没办法满足运行期索引和迭代的需求,好在我们还有其他的方法可以实现。需要boost库的支持。
4 std::size()
C++17开始,可以使用std::size()获取传统C数组的个数。int myArray[]={1,2,3,4};std::cout<<std::size(myArray)<<std::endl;
5 std::optional
optional意为可选值,需要传入一个类型,表示该类型的值存在或不存在。通常用于函数返回值,比如下面的用法:
//std::optional使用示例,表示可以存在或不存在的值#include <iostream>#include <optional>using namespace std;//定义一个函数,返回值是可选值,既可以是int,也可以是其他非类型optional<int> getData(bool it){if (it)return 42;return nullopt;}int main(){//调用函数,保存返回值optional<int> data1{getData(true)};optional<int> data2{getData(false)};//判断变量是否有值(两种方式),如果有打印值if (data1.has_value()){cout << data1.value() << endl;}if (data2){//不经判断直接访问会抛出exceptioncout << *data2 << endl;}//data2没有值,但可以通过以下方式打印它保存了什么cout << "what is in data? " << data2.value_or(0) << endl;}
6 emplace操作
C++11开始支持emplace操作,emplace和push_back/insert之类的修改方式不同的是,emplace直接占用容器的内存空间创建需要保存的对象(原位调用构造函数),不需要提前创建对象再复制或移动(move)到容器中。
emplace主要有以下基本成员函数,不同类型的容器支持情况不同:
emplace(const_iterator pos, Args&&... args):直接于 pos 前插入元素到容器中emplace_after(const_iterator pos, Args&&... args):在容器中的指定位置后插入新元素emplace_hint(const_iterator hint, Args&&... args):插入新元素到尽可能接近恰在 hint 前的位置emplace_front(Args&&... args):插入新元素到容器起始- C++11返回void
- C++17开始返回构造对象的引用
emplace_back(Args&&... args):添加新元素到容器尾- C++11返回void
- C++17开始返回构造对象的引用
7 std::span
span是C++20引入,表示连续相邻的序列,可以用于表示vector,array和C原始数组的一部分或全部,类似于string_view。
span主要包含两个成员:指向容器类型T的指针和表示的范围大小。span只是顺序序列容器的一个指针视图,它并不会复制原始数据(可以通过span修改数据,因为内部保存容器数据指针),所以作为参数传递时更加快捷。
两个比较重要的成员函数:
data():返回原始容器或数组的指针,可以用这个指针来修改数据`subspan(std::size_t Offset,
std::size_t Count)`:从span基础上再创建新的子视图
示例如下:
void print(span<int> values){for (const auto &value : values){cout << value << " ";}cout << endl;}int main(){vector v{11, 22, 33, 44, 55, 66};//直接传vector,因隐式转换为全范围的spanprint(v);//创建全范围span作为参数span mySpan{v};print(mySpan);//从全范围span创建子spanspan subspan{mySpan.subspan(2, 3)};print(subspan);//从vector创建span,因为第一个参数是指针,所以需要调用data()print({v.data() + 2, 3});//从array创建spanarray<int, 5> arr{5, 4, 3, 2, 1};print(arr);print({arr.data() + 2, 3});//从C数组创建spanint carr[]{9, 8, 7, 6, 5};print(carr); // The entire C-style array.print({carr + 2, 3}); // A subview of the C-style array.}
