C++ 包装器—function

简介: C++ 包装器—function

一、什么是function?

       在C++中,std::function是一种模板类,它用于表示任意类型的函数或方法,可以作为函数参数或返回类型。std::function的提出可以用于替代函数指针,以此来降低使用回调函数的难度,它比普通函数指针更加的灵活和便利。

       std::function的主要特点包括:

  • 可以存储和执行任何类型的函数或方法,只要该函数或方法能够被复制(即它可以有一个副本)。
  • 可以方便地对函数进行比较、拷贝、移动等操作。
  • 可以通过std::bind函数或其他方式创建具有特定参数和返回类型的函数实例。
template< class R, class... Args >
  class function<R(Args...)>;

对于以上各个部分的解析:

       R表示函数的返回类型,Args表示函数的参数列表。std::function模板类生成的类可以用来存储任何符合这些类型的函数。


一个简单的例子:

#include <iostream>
#include <functional>
// 定义一个简单的函数
int add(int a, int b) {
    return a + b;
}
int main() {
    // 创建一个std::function实例,存储add函数
    std::function<int(int, int)> func = add;
    // 使用std::function执行add函数
    int result = func(1, 2);
    std::cout << "Result: " << result << std::endl;
    return 0;
}

       在这个例子中,我们首先定义了一个简单的函数add,然后使用std::function创建了一个函数实例func,并将其初始化为add函数。最后,我们使用func执行add函数,并输出结果。

需要注意的是,std::function并不是C++标准库的一部分,而是C++11引入的新特性之一。因此,在使用std::function之前,需要确保你的编译器已经支持C++11或更高版本。

      对以上例子进行详细的分析:function的R的定义是根据add函数的返回类型定义为int,函数的参数列表为两个int也是因为add函数的两个传参为int。


二、function使用详解

包装基本的函数(普通、仿函数、lambda)

#include<iostream>
#include<functional>
#include<string>
#include <map>
using namespace std;
//普通函数
void swap_func(int& r1, int& r2)
{
  int tmp = r1;
  r1 = r2;
  r2 = tmp;
}
//仿函数
struct Swap
{
  void operator()(int& r1, int& r2)
  {
    int tmp = r1;
    r1 = r2;
    r2 = tmp;
  }
};
int main()
{
  int x = 0, y = 1;
  cout << x << " " << y << endl;
//lambda
  auto swaplambda = [](int& r1, int& r2) {
    int tmp = r1;
    r1 = r2;
    r2 = tmp;
  };
  function<void(int&, int&)> f1 = swap_func;
  f1(x, y);
  cout << x << " " << y << endl << endl;
  function<void(int&, int&)> f2 = Swap();
  f2(x, y);
  cout << x << " " << y << endl << endl;
  function<void(int&, int&)> f3 = swaplambda;
  f3(x, y);
  cout << x << " " << y << endl << endl;
  map<string, function<void(int&, int&)>> cmdOP = {
    {"函数指针", swap_func},
    {"仿函数", Swap()},
    {"lambda", swaplambda},
  };
  cmdOP["函数指针"](x, y);
  cout << x << " " << y << endl << endl;
  cmdOP["仿函数"](x, y);
  cout << x << " " << y << endl << endl;
  cmdOP["lambda"](x, y);
  cout << x << " " << y << endl << endl;
  return 0;
}

包装静态成员函数

包装静态成员函数,我们需要指定类域,然后加上&用于成员函数取地址,当然因为是静态成员函数其实可以不加&,但是为了统一,我们最好加上。

1.class Plus
{
public:
  static int plusi(int a, int b)
  {
    return a + b;
  }
};
int main()
{
  // 成员函数取地址,比较特殊,要加一个类域和&
  function<int(int, int)> f1 = &Plus::plusi;
  cout << f1(1, 2) << endl;
  return 0;
}


包装普通成员函数

由于普通成员函数的包装还存在一个this,因此function中还需要传this,因此我们可以像以下的两种方式包装:一、传递指针,用指针去调用成员函数指针。二、传递对象,用对象去调用函数指针。(第二种可以理解成做了特殊处理)
class Plus
{
public:
  static int plusi(int a, int b)
  {
    return a + b;
  }
  double plusd(double a, double b)
  {
    return a + b;
  }
};
int main()
{
  // 成员函数取地址,比较特殊,要加一个类域和&
  function<int(int, int)> f1 = &Plus::plusi;
  cout << f1(1, 2) << endl;
  function<double(Plus*, double, double)> f2 = &Plus::plusd;
  Plus ps;
  cout << f2(&ps, 1.1, 2.2) << endl;
  function<double(Plus, double, double)> f3 = &Plus::plusd;
  cout << f3(Plus(), 1.11, 2.22) << endl;
  return 0;
}

三、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);

       bind函数用于将一个可调用对象(如函数、lambda表达式等)与一组参数绑定,生成一个新的可调用对象。

       第一个模板声明template <class Fn, class... Args> /* unspecified */ bind (Fn&& fn, Args&&... args);表示bind函数接受一个可调用对象fn和一组参数args,返回一个新的可调用对象。其中,Fn是可调用对象的类型,Args是参数的类型,...表示可变参数包。

       第二个模板声明template <class Ret, class Fn, class... Args> /* unspecified */ bind (Fn&& fn, Args&&... args);表示bind函数接受一个可调用对象fn、一个返回类型Ret和一组参数args,返回一个新的可调用对象。其中,Ret是返回类型的类型,Fn是可调用对象的类型,Args是参数的类型,...表示可变参数包。

调整参数的顺序

如下我们可以用function进行bind改变函数传参的顺序,根据(placeholder::_第几个参数)来按照对应的位置调整顺序。如下:

int Sub(int a, int b)
{
  return a - b;
}
int main()
{
  function<int(int, int)> f1 = Sub;
  cout << f1(10, 5) << endl;
  // 调整参数顺序
  function<int(int, int)> f2 = bind(Sub, placeholders::_2, placeholders::_1);
  cout << f2(10, 5) << endl;
    return 0;
}

调整参数个数,用bind写死参数

我们也可以用function进行bind通过写死一些参数来调整参数的个数,当然我们也是需要用(placeholder::_第几个参数)来按照对应的位置调整。如下:

int Sub(int a, int b)
{
  return a - b;
}
int main()
{
  function<int(int, int)> f1 = Sub;
  cout << f1(10, 5) << endl;
  // 调整参数顺序
  function<int(int, int)> f2 = bind(Sub, placeholders::_2, placeholders::_1);
  cout << f2(10, 5) << endl;
  // 调整参数个数,有些参数可以bind时写死
  function<int(int)> f3 = bind(Sub, 20, placeholders::_1);
  cout << f3(5) << endl;
  return 0;
}

用bind调整来包装成员函数

class Plus
{
public:
  static int plusi(int a, int b)
  {
    return a + b;
  }
  double plusd(double a, double b)
  {
    return a + b;
  }
};
int main()
{
  function<double(Plus*, double, double)> f2 = &Plus::plusd;
  Plus ps;
  cout << f2(&ps, 1.1, 2.2) << endl;
  function<double(Plus, double, double)> f3 = &Plus::plusd;
  cout << f3(Plus(), 1.11, 2.22) << endl;
//用bind来写死Plus()从而简化代码
  function<double(double, double)> f4 = bind(&Plus::plusd, Plus(), placeholders::_1, placeholders::_2);
  cout << f4(1.11, 2.22) << endl;
  return 0;
}

               感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o!

相关文章
|
2月前
|
存储 编译器 C语言
从C语言到C++_34(C++11_下)可变参数+ lambda+function+bind+笔试题(下)
从C语言到C++_34(C++11_下)可变参数+ lambda+function+bind+笔试题
36 5
|
2月前
|
程序员 编译器 C++
C++中的函数重载(Function Overloading)
C++中的函数重载(Function Overloading)
20 2
|
2月前
|
算法 编译器 C语言
从C语言到C++_34(C++11_下)可变参数+ lambda+function+bind+笔试题(中)
从C语言到C++_34(C++11_下)可变参数+ lambda+function+bind+笔试题
28 2
|
2月前
|
算法 编译器 C语言
从C语言到C++_34(C++11_下)可变参数+ lambda+function+bind+笔试题(上)
从C语言到C++_34(C++11_下)可变参数+ lambda+function+bind+笔试题
17 1
|
26天前
|
算法 编译器 C++
C++多态与虚拟:函数重载(Function Overloading)
重载(Overloading)是C++中的一个特性,允许不同函数实体共享同一名称但通过参数差异来区分。例如,在类`CPoint`中,有两个成员函数`x()`,一个返回`float`,另一个是设置`float`值。通过函数重载,我们可以为不同数据类型(如`int`、`float`、`double`)定义同名函数`Add`,编译器会根据传入参数自动选择正确实现。不过,仅返回类型不同而参数相同的函数不能重载,这在编译时会导致错误。重载适用于成员和全局函数,而模板是另一种处理类型多样性的方式,将在后续讨论中介绍。
|
2月前
|
存储 算法 对象存储
【C++入门到精通】function包装器 | bind() 函数 C++11 [ C++入门 ]
【C++入门到精通】function包装器 | bind() 函数 C++11 [ C++入门 ]
30 1
|
2月前
|
Java 编译器 Linux
【C++11(二)】lambda表达式以及function包装器
【C++11(二)】lambda表达式以及function包装器
|
2月前
|
存储 算法 C++
C++11:lambda表达式 & 包装器
C++11:lambda表达式 & 包装器
18 0
|
10天前
|
JavaScript 前端开发
JavaScript函数是代码复用的关键。使用`function`创建函数
【6月更文挑战第22天】JavaScript函数是代码复用的关键。使用`function`创建函数,如`function sayHello() {...}`或`function addNumbers(num1, num2) {...}`。调用函数如`sayHello()`执行其代码,传递参数按值进行。函数可通过`return`返回值,无返回值默认为`undefined`。理解函数对于模块化编程至关重要。
20 4
|
4天前
|
运维 负载均衡 Serverless
函数计算产品使用问题之yaml如果写多个function,可不可以yaml在构建的时候能构建多个函数
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。