返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++11新增的包装器详解
  • 513
分享到

C++11新增的包装器详解

2024-04-02 19:04:59 513人浏览 薄情痞子
摘要

目录functionbindfunction 目前,我们的知识深度已知的可调用对象类型有: 函数指针仿函数 / 函数对象lambda表达式 现在我们有一个函数模板 templa

function

目前,我们的知识深度已知的可调用对象类型有:

  • 函数指针
  • 仿函数 / 函数对象
  • lambda表达式

现在我们有一个函数模板

   template<class F, class T>
   T useF(F f, T x)
   {
  		static int count = 0;
  	  	cout << "count:" << &count << endl;
     	return f(x);
   }

对于函数模板,编译器会根据实参,按照模板定义出一份特定的函数。

函数内部的静态成员变量是属于函数的,无论调用多少次该函数,都只会定义出一个。

记住上面这两个知识点,现在增加一个函数和仿函数,用来测试useF函数模板

int Sub(int num)
{
	return (num - 2);
}
struct Func
{
	int operator()(int num)
	{
		return (num - 3);
	}
};
int main()
{
	// 函数名
	cout << useF(Sub, 4) << endl;
	// 函数对象
	cout << useF(Func(), 4) << endl;
	// lambda表达式
	cout << useF([](int d)->int{ return (d - 4); }, 11.11) << endl;
	return 0;
}

解释运行结果:我们在函数模板内部实现打印静态成员变量,发现三次打印的cout地址不一样。然而静态成员变量是属于函数的,一个函数的静态成员变量无论调用多少次都只有一份。这说明是三个不同的函数调用。

以lambda表达式为例,一个lambda表达式语句就生成一个自定义类型(仿函数),那么多次调用会根据模板产生非常多的函数。

int main()
{
	// 函数名
	cout << useF(Sub, 4) << endl;
	// 函数对象
	cout << useF(Func(), 4) << endl;
	// lamber表达式
	cout << useF([](int d)->int{ return (d - 4); }, 11.11) << endl;
	cout << useF([](int d)->int { return (d - 4); }, 11.11) << endl;
	return 0;
}

其他可调用对象的类型也是很多的,许多的函数指针,许多的仿函数类,许多的lambda表达式……。类型太丰富了!对于一个模板而言,类型不同,就会对应定义出一份。模板的效率也降低了太多。

c++11提供了包装器,包装器可以将可调用对象统一包装成一个类型。function就是一个包装器,也可称为适配器

function

#include <functional>
template <class Ret, class... Args> 
class function<Ret(Args...)>;

Ret(Args…):第一个模板参数类型(参数包)

测试:

template<class F, class T>
T useF(F f, T x)
{
	static int count = 0;
	//cout << "count:" << ++count << endl;
	cout << "count:" << &count << endl;
	return f(x);
}
int main()
{
	function<int(int)> f1 = [](int d)->int { return (d - 4); };
	function<int(int)> f2 = [](int d)->int { return (d - 4); };
	function<int(int)> f3 = [](int d)->int { return (d - 4); };
	// lamber表达式
	cout << useF(f1, 5) << endl;
	cout << useF(f2, 5) << endl;
	cout << useF(f3, 5) << endl;
	return 0;
}

上面调用的都是同一个函数。

一个lambda表达式语句会生成一个类,上面有三个lambda表达式语句,生成三个类。使用function包装器将这些可调用对象包装成了一个类型,模板也就只需要定义出一份特定的,极大地提升了模板的效率。

【普通函数指针】

包装用法:function<Ret(Args...)> 对象名 = 函数指针

//例如
int Sub(int x, int y)
{
	return x - y;
}
int main(void)
{
	//包装函数指针
	function<int(int, int)> f1 = Sub;
	cout << f1(12, 8) << endl;
	return 0;
}

【仿函数】

包装用法:function<Ret(Args……) 对象名 = 仿函数类()

class Sub
{
public:
	int operator()(int x, int y)
	{
		return (x - y);
	}
};
int main(void)
{
	function<int(int, int)> f2 = Sub();
	return 0;
}

【静态类成员函数指针】

包装方法:function<Ret(Args……) 对象名 = &类域::函数指针

& 可以不加,不影响结果,但是加上要更优一些。

class Sub
{
public:
	static int SubStatic(int x, int y)
	{
		return (x - y);
	}
};
int main(void)
{
	function<int(int, int)> f2 = &Sub::SubStatic;
	cout << f2(10, 3) << endl;
	function<int(int, int)> f3 = Sub::SubStatic;
	cout << f2(10, 3) << endl;
	return 0;
}

【非静态类成员函数指针】

包装方法:function<Ret(类域名, Args……) 对象名 = &类域::函数指针

class Sub
{
public:
	int SubMember(int x, int y)
	{
		return (x - y);
	}
};
int main(void)
{
	function<int(Sub, int, int)> f4 = Sub::SubMember;
	cout << f4(Sub(), 3, 1) << endl;
	return 0;
}

非静态类成员函数指针包装后,使用包装后的对象进行调用,第一个参数,必须是类名。

【lambda表达式】

包装方法:function<Ret(Args……) 对象名 = lambda表达式

int main(void)
{
	function<double(double, double)> f5 = [](double x, double y)mutable->double {return x - y; };
	cout << f5(2.23, 1.11) << endl;
	return 0;
}

bind

bind也是一个包装器。

作用一:调整参数的顺序

普通函数指针的包装方法:function<Ret(Args...)> 对象名 = bind(函数指针,newArgs……)

int Sub(int x, int y)
{
	return x - y;
}
int main(void)
{
	//function、bind包装函数指针
	function<int(int, int)> f1 = Sub;
	//将第一个参数和第二个参数交换
	function<int(int, int)> f2 = bind(Sub, placeholders::_2, placeholders::_1);
	cout << f1(12, 8) << endl;
	cout << f2(12, 8) << endl;
	return 0;
}

placeholders::_n,表示当前function类中参数包的第n个参数。

希望怎么调整参数的顺序,就在调用bind函数时,传递什么样的参数顺序。bind函数传参时,使用placeholders::_n。

作用二、指定某个参数的值

#include <iOStream>
#include <functional>
using namespace std;
int Sub(int x, int y)
{
	return x - y;
}
int main(void)
{
	//function、bind包装函数指针
	function<int(int, int)> f2 = bind(Sub, 10, placeholders::_2);
	cout << f2(12, 8) << endl;
	return 0;
}

使用function和bind包装过后,并且指定了某个参数的值。function实例化的时候可以省略掉指定了值的参数的参数类型。省略掉后要注意维护bind函数内的参数包。

int Sub(int x, int y)
{
	return x - y;
}
int main(void)
{
	//function、bind包装函数指针
	function<int(int)> f2 = bind(Sub, 10, placeholders::_1);
	cout << f2(8) << endl;
	return 0;
}

可得出结论,bind的间接作用:调整参数的个数。

到此这篇关于C++11新增的包装器详解的文章就介绍到这了,更多相关C++包装器内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++11新增的包装器详解

本文链接: https://lsjlt.com/news/166075.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C++11新增的包装器详解
    目录functionbindfunction 目前,我们的知识深度已知的可调用对象类型有: 函数指针仿函数 / 函数对象lambda表达式 现在我们有一个函数模板 templa...
    99+
    2024-04-02
  • 【C++】C++11 ~ 包装器解析
    🌈欢迎来到C++专栏~~包装器解析 ...
    99+
    2023-09-12
    c++ java 开发语言
  • C++11学习之包装器解析
    目录概念类型统一例题:求解逆波兰表达式包装器的意义bind 包装器bind 绑定固定参数调整传参顺序bind包装器的意义概念 function包装器 也叫作适配器。C++中的func...
    99+
    2023-02-13
    C++11包装器解析 C++11包装器 C++ 包装器
  • C#11新特性使用案例详解
    目录前言新特性之原始字符串使用案例原始字符串使用需要注意的地方什么情况下需要超过三个双引号开头尾引号和尾引号前面的换行符不包括在最终内容中结尾的三个引号不另起一行行不行和内插字符一起...
    99+
    2024-04-02
  • C++11 中的override详解
    目录1 公有继承1.1 纯虚函数 (pure virtual)1.2 普通虚函数1.2.1 方法一1.2.2 方法二1.3 非虚函数2 重写 (override)小结:参考资料1 公...
    99+
    2024-04-02
  • 深入解析C++11 lambda表达式/包装器/线程库
    目录零、前言一、lambda表达式1、lambda的引入2、lambda表达式语法3、捕获列表说明4、函数对象与lambda表达式二、包装器1、function包装器2、bind 概...
    99+
    2024-04-02
  • C++11中的chrono库详解
    目录前言1、记录时长的duration2、表示时间点的time_point3、获取系统时钟的clocks前言 C++11提供了日期时间相关的库chrono,通过chrono库可以很方...
    99+
    2023-03-19
    C++11中的chrono库 C++11 chrono库
  • 详解C++11中的线程库
    目录一、线程库的介绍1.1. 使用时的注意点1.2. 线程函数参数1.3. join与detach二、原子性操作库2.1. atomic2.2. 锁三、使用lambda表达式创建多个...
    99+
    2024-04-02
  • C++11新特性之变长参数模板详解
    目录C++11 变长参数模板变长函数参数包如何解参数包sizeof()获得函数参数个数递归模板函数变参模板展开结论C++11 变长参数模板 在C++11之前,无论是类模板 还是函数...
    99+
    2024-04-02
  • 详解C++11的std::addressof源码解析
    目录1、源码准备2、std::addressof简介3、std::addressof源码解析4、总结1、源码准备 本文是基于gcc-4.9.0的源代码进行分析,std::addre...
    99+
    2024-04-02
  • C++11新特性之随机数库(Random Number Library)详解
    目录从前的随机数随机数库(Random Number Library)随机数引擎随机数分布类生成平均分布的整数生成平均分布的实数生成正态分布的实数生成概率可控的布尔值补充:真正的随机...
    99+
    2024-04-02
  • 详解C++11中的类型推断
    C++11中的类型推断 C++11中为了更好的支持泛型编程,提供了 auto和decltype两个关键词,目的就是提供编译阶段的自动类型推导。 1.auto关键词的新意义 在C++9...
    99+
    2023-01-31
    C++11类型推断 C++11推断
  • C++11 中的std::function和std::bind详解
    目录1. 可调用对象2. std::function3. std::bind3.1 std::bind绑定普通函数3.2 std::bind绑定一个成员函数3.3 绑定一个引用参数4...
    99+
    2024-04-02
  • 一文详解C++11中的lambda函数
    目录1.lambda函数语法1.1 捕获列表1.2 mutable修饰符1.3 匿名lambda函数2.lambda与STL我可以明确告诉你:lambda函数是C++11中最重要的,...
    99+
    2023-02-07
    C++11 lambda函数使用 C++11 lambda函数 C++11 lambda
  • 详解JavaScriptes6的新增数组方法
    目录1. forEach()2. arr.filter()3. arr.every()4. arr.map()5. arr.some()总结 1. forEach() 遍历数组,无r...
    99+
    2024-04-02
  • C++11新特性之右值引用与完美转发详解
    目录一、左值与右值二、左值引用与右值引用三、右值引用应用1.移动构造与移动赋值1.模拟实现的string2.移动构造3.移动赋值四、默认移动构造和移动赋值重载函数五、完美转发1.万能...
    99+
    2024-04-02
  • 详解C++11中绑定器bind的原理与使用
    目录bind1st和bind2nd什么时候会用到函数对象绑定器bind1st和bind2nd的底层实现原理bind1st和bind2nd什么时候会用到 bind用于绑定可调用 (Ca...
    99+
    2022-12-09
    C++11绑定器bind C++11绑定器 C++11 bind
  • C++11系列学习之可调用对象包装器和绑定器
    目录旧标准的缺陷繁杂的调用对象问题浮出水面std::function小试牛刀std::bind作用占位符高级用法配合使用旧标准的缺陷 学习新标准的语法之前,先来聊聊旧标准存在的缺陷,...
    99+
    2024-04-02
  • 使用c++11 constexpr时遇到的坑详解
    最近在使用constexpr的时候无意中踩了个小坑。 下面给个小示例: #include <iostream> constexpr int n = 10; cons...
    99+
    2024-04-02
  • 详解C++11中模板的优化问题
    1. 模板的右尖括号 在泛型编程中,模板实例化有一个非常繁琐的地方,那就是连续的两个右尖括号(>>)会被编译器解析成右移操作符,而不是模板参数表的结束。我们先来看一段关...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作