当前位置: 首页 > article >正文

C++11(中)

新增默认成员函数

C++11之前,默认成员函数有六个,构造函数,析构函数,拷贝构造,拷贝赋值重载,取地址重载,const 取地址重载。

C++11增加了 移动构造 和 移动赋值重载

如果类没有实现移动构造,且没有实现析构,拷贝,拷贝赋值重载中的任意一个,才会生成默认的移动构造。

默认的移动构造对内置类型进行按字节拷贝,自定义类型调用它的移动构造,该自定义类型没有实现移动构造就调用拷贝构造。

默认的移动赋值的生成和调用逻辑也类似。

新增关键字

default : 强制生成默认的成员函数

delete :强制禁用默认的成员函数

可变模板参数

C++11之后,模板可以接受多个参数

// Args是一个模板参数包,args是一个函数形参参数包
// 声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数。
template <class ...Args>
void ShowList(Args... args)
{}
//引用接收(万能引用)  
template <class ...Args>
void ShowList(Args&&... args)
{}

实现一个打印函数

//递归的出口
void _my_print() { 
    ;
}
//递归解析参数包 (args...)
template <class T, class... Args> 
void _my_print(T x, Args... args) {  
    cout << x << endl; 
    _my_print(args...);
}
//打印函数,可以传入不同类型的参数
template <class... Args>
void my_print(Args... args) {
    _my_print(args...);            
}

调用一下

int main() { 
    my_print(2025,1.1, 'c', string("C++"));   
	return 0;
}

结果如下

上述代码是在编译时,递归式解析参数包

STL容器的 emplace_back 系列

STL的容器增加了 emplace_back 接口,功能和和 push_back 一样。

以 std::vector 为例,看一下接口

template< class... Args >
void emplace_back( Args&&... args );

emplace_back 支持了模板的可变参数,假如我用插入一个 pair<string, int> 类型的数据,emplace_back 只需传入 string 和 int 类型的参数即可,无需构造临时的 pair<string, int> 对象。

我们分析如下代码,来理解一下

	vector<pair<string, int>> v; 
	v.push_back({ "西瓜", 2 });           
    v.emplace_back("西瓜", 2);

首先,{ “西瓜”, 2 } 是列表初始化,相当于隐式类型转换,会调用pair的构造函数来构造出pair<string, int>类型的临时对象,该临时对象属于右值,会调用vector的移动构造转移资源,所以

v.push_back({ “西瓜”, 2 }) 插入是pair的构造 + vector的移动构造

而 emplace_back 相当于传参给vector的构造,vector直接构造pair<string, int>类型对象并插入容器中。

v.emplace_back(“西瓜”, 2) 的插入只调用了vector的构造

所以从效率上说:对于浅拷贝的类或内置类型,emplace_back 效率更高。对于深拷贝的类,效率相差不大。

lambda表达式

lambda 表达式是一个匿名函数对象,语法如下

[捕捉列表](参数)mutable -> 返回值类型 {函数体};

lambda 表达式中很多内容可以省略

如下代码

auto func = []() {};
func();

写一个add函数,如下代码

//也可以不带返回值类型 [](int a, int b) { return a + b; };
auto add = [](int a, int b)->int { 
    return a + b;
    };
cout << add(3, 4) << endl;

捕捉列表可以捕捉当前作用域的变量,加 & 符号表示传引用捕捉,不加表示传值捕捉(lambda表达式会拷贝一份新的副本)

如下代码,传值捕捉,新的副本具有 const属性

int main() { 
    int a = 3, b = 4;
	//lambda表达式中的 a b 是 mian 函数a b 的一份拷贝
    auto add = [a, b]() { return a + b; };
    cout << add() << endl;

取消传值捕捉的 const 属性需要加 mutable 关键字

    auto add = [a, b]() mutable { return a + b; } ;

传引用捕捉如下代码

    int a = 3, b = 4;
    auto add = [&a, &b]() mutable { a++; b++; };
    add();
    cout << a << b << endl;

其他的一些捕捉凡是如下,可以和上述的捕捉方式混合使用。

[=]:表示值传递方式捕获所有父作用域(包含lambda函数的语句块)中的变量(包括this)

[&]:表示引用传递捕捉所有父作用域中的变量(包括this)

[this]:表示值传递方式捕捉当前的this指针

function 包装器

function 的本质是类模板,用来包装一切可调用对象。

可调用对象包括:函数指针,仿函数,函数名,lambda表达式。

// 类模板原型如下
template <class T> function;     // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;
//Ret: 被调用函数的返回类型
//Args…:被调用函数的形参

std::function 的实例化需要指定返回值类型,和参数类型

function<返回值类型(参数类型...)> 对象名 = 可调用对象;

如下示例

int f(int a, int b)
{
 return a + b;
}
std::function<int(int, int)> func1 = f;
//调用func1
func1(1, 2);

function 类模板重载了 () ,调用该对象可以和仿函数一样。

对于非静态成员函数,可调用对象需要 & 符号,静态成员函数不需要

class op {  
public:
    static int sub(int a, int b) {
        return a - b;
    }
    int sum(int a, int b) {
        return a + b;       
    }
};

function<int(op*, int, int)> f1 = &op::sum; 
function<int(int, int)> f2 = op::sub;

std::bind

bind 是一个函数模板,接受一个可调用对象,生成一个新的可调用对象。bind 用来调整参数的顺序和个数。

// 原型如下:
template <class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);
// with return type (2) 
template <class Ret, class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);

以上述的 op 类举例,绑定成员函数

op p;
function<int(int, int)> f3 = bind(&op::sum, &p, placeholders::_1, placeholders::_2);        
function<int(int, int)> f4 = bind(&op::sum, p, placeholders::_1, placeholders::_2);

placeholders::_n ,是占位符,不需要绑定的参数用 placeholders::_n 表示。


http://www.kler.cn/a/527769.html

相关文章:

  • Java 大视界 -- Java 大数据在自动驾驶中的数据处理与决策支持(68)
  • 力扣动态规划-16【算法学习day.110】
  • CSS 溢出内容处理:从基础到实战
  • Linux网络 | 网络层IP报文解析、认识网段划分与IP地址
  • MySQL注入中load_file()函数的使用
  • Redis篇 Redis如何清理过期的key以及对应的解决方法
  • 5 长度和距离计算模块(length.rs)
  • 《苍穹外卖》项目学习记录-Day7导入地址簿模块功能代码
  • SSM开发(十) SSM框架协同工作原理
  • 菜鸟之路Day13一一方法引用
  • Flutter Candies 一桶天下
  • Windows系统中Docker可视化工具对比分析,Docker Desktop,Portainer,Rancher
  • python中字典用法
  • eBay管理工具:提升运营效率的利器
  • UE学习日志#16 C++笔记#2 基础复习2
  • 【股票数据API接口44】如何获取股票指历史分时MA数据之Python、Java等多种主流语言实例代码演示通过股票数据接口获取数据
  • sublime_text的快捷键
  • C++11新特性之tuple元组
  • Day49:添加字典元素
  • CSS 背景与边框:从基础到高级应用
  • I2C基础知识
  • 【项目集成Husky】
  • MATLAB中lineBoundary函数用法
  • Snowflake企业权限管理
  • 动态规划DP 最长上升子序列模型 导弹防御模型(题目分析+C++完整代码实现)
  • 基于Hutool的Merkle树hash值生成工具