前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C/C++开发基础——函数对象与std::function模板

C/C++开发基础——函数对象与std::function模板

作者头像
Coder-Z
发布2023-02-23 17:29:11
7600
发布2023-02-23 17:29:11
举报

本章主要内容:

一,函数对象

1.函数对象的概念

2.函数对象的应用

3.标准库中的函数对象

4.函数对象的传参

5.C++代码样例

二,标准库中的std::function模板

1.std::function简介

2.std::function具体用法

3.C++代码样例

三,参考阅读

一,函数对象

1.函数对象的概念

函数对象可以像函数那样被直接调用。

函数对象(function objects)又被称为仿函数(functors)。

函数对象可以被当作一个值赋给另一个变量,也可以作为实参传递给其他函数,或者作为其他函数的返回结果。

函数对象与函数指针相似,函数对象的行为和函数差不多,但是与函数指针不同的是,函数对象是完整的类对象,里面包含着成员变量和多个成员函数。

函数对象的用法如下:

代码语言:javascript
复制
//class可以换成struct
class FunctionObjName 
{
public:
    ReturnType operator()(ParamType1, ... , ParamTypeN){
        process code
    }
};

2.函数对象的应用

函数对象的实现,本质上是在类中完成函数调用运算符的重载。因此,使用函数对象的重点在于重载"operator()"。

使用函数对象的步骤:

step.01: 新建一个类,在类中定义一个重载的函数调用运算符

代码语言:javascript
复制
class Less
{
public:
    bool operator()(int a,int b) const;
};
//Less类的成员函数:函数调用运算符operator()

step.02: 定义函数运算符operator()的具体操作

代码语言:javascript
复制
bool Less::operator()(int a, int b) const
{
    return a < b;
}

step.03: 新建一个函数对象,并像调用函数一样调用函数对象

代码语言:javascript
复制
Less less_obj;
const bool_is_less = less_obj(5, 6);

3.标准库中的函数对象

STL标准库中提供了很多函数对象的类模板,它们都包含在头文件functional中。

例如上面提到的Less类,可以使用标准库中的"std::less<int>less"。从C++14标准开始,可以省略类型实参,例如"std::less<>less"。

标准库中常见的函数对象:

调用方式样例:

代码语言:javascript
复制
//方式一,直接调用
std::cout << std::plus<int>()(4, 5) << std::endl;
//方式二,实例化一个新的类,然后调用
std::plus<int> plus_obj;
std::cout << plus_obj(4, 5) << std::endl;

4.函数对象的传参

关于调用的时候传参,使用函数指针的开发场景更多时候是通过回调函数(超链接)来实现的,但是使用函数对象的开发场景有更加简洁的传参方式,它可以将用户传的参数放在对象的成员变量中。

代码样例:

代码语言:javascript
复制
#include <cmath>
class Nearer
{
public:
    Nearer(int value):{
        n=value;
    }
    bool operator()(int a,int b) const {
        return std::abs(a - n) < std::abs(b - n);
    };
private:
    int n;
};

5.C++代码样例

Demo_1:

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <cmath> //For std::abs()
//用于对vector中逐个元素进行操作的模板函数
template <typename T, typename Process_type>
const T* find_optimum(const std::vector<T>& values, Process_type process)
{
       if (values.empty())
              return nullptr;
       const T* res = &values[0];
       for (size_t i = 1; i < values.size(); ++i)
       {
              if (process(values[i], *res))
              {
                      res = &values[i];
              }
       }
       return res;
}
class Nearer
{
public:
       Nearer(int value): n(value){ }
       //重载函数调用运算符
       bool operator()(int a, int b) const {
              return std::abs(a - n) < std::abs(b - n);
       };
private:
       int n;
};
class Less
{
public:
       //重载函数调用运算符
       bool operator()(int a, int b) const {
              return a < b;
       }
};
int main()
{
       Less less_obj;
       std::vector<int> numbers{ 23, 18, 17, 66, 40, 50 };
       std::cout << "Minimum element: " << *find_optimum(numbers, less_obj) <<  std::endl;
       std::cout << "The number nearest 36 is: " << *find_optimum(numbers, Nearer(50))  << std::endl;
}

运行结果:

代码语言:javascript
复制
Minimum element: 17
The number nearest 36 is: 50

Demo_2:

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <algorithm>
class MeanValue {
private:
       int num;
       int sum;
public:
       MeanValue() : num(0), sum(0) {
       }
       //function call
       void operator()(int elem) {
              ++num;
              sum += elem;
       }
       double get_mean_value() {
              return static_cast<double>(sum) / static_cast<double>(num);
       }
};
int main()
{
       std::vector<int> data_list = { 1, 2, 3, 4, 5, 6, 7, 8};
       MeanValue mv_obj = std::for_each(data_list.begin(), data_list.end(),  MeanValue());
       std::cout << "mean value: " << mv_obj.get_mean_value() << std::endl;
}

运行结果:

代码语言:javascript
复制
mean value:4.5

二,标准库中的std::function模板

1.std::function简介

std::function<>是C++11标准引入的类模板。 std::function<>专门用来包装可调用的函数对象。 在"<>"里面传入返回值类型和传参类型就可以开始使用std::function<>了。 std::function<>用法如下:

代码语言:javascript
复制
std::function<ReturnType(ParamType1, ... , ParamTypeN)>

std::function<>类模板的特点是,可以通过指定的类型参数,来统一处理设定返回值类型和参数类型 的各种函数对象。 std::function<int(int)> 可以用来专门调用返回值是int类型,形参是int类型的函数对象。 因此,有了std::function<>,不同实现的各种函数对象可以共用同一种调用形式(call signature)。 实例化以后的std::function<>,例如std::function<int(int)>,可以被理解为是某种特定调用形式的一个容器。

2.std::function具体用法

std::function<>被实例化以后可以调用: 普通函数 函数对象 lambda表达式。 用法演示: 应用场景:std::function<int(int, int)> 如下定义了返回值为int类型,传参为(int, int)的三种实现方式: add -->普通函数实现 mod -->lambda表达式实现 divide -->函数对象实现(struct某种程度上用法和对象一样)

代码语言:javascript
复制
int add(int i, int j){return i + j;}
auto mod = [](int i, int j){return i % j;};
struct divide
{
    int operator()(int m, int n)
    {
        return m / n;
    }
};

std::function调用它们的方式如下:

代码语言:javascript
复制
//初始化
std::function<int(int, int)> f1 = add;
std::function<int(int, int)> f2 = divide();
std::function<int(int, int)> f3 = mod;
//调用
std::cout << f1(4, 2) << std::endl;
std::cout << f2(4, 2) << std::endl;
std::cout << f3(4, 2) << std::endl;

完整C++代码实现:

代码语言:javascript
复制
#include <iostream>
#include<functional>
int add(int i, int j) { return i + j; }
auto mod = [](int i, int j) {return i % j; };
struct divide
{
    int operator()(int m, int n)
    {
           return m / n;
    }
};
int main()
{
    std::function<int(int, int)> f1 = add;
    std::function<int(int, int)> f2 = divide();
    std::function<int(int, int)> f3 = mod;
    std::function<int(int, int)> f4 = [](int i, int j) {return i * j; };;
    std::cout << f1(4, 2) << std::endl;
    std::cout << f2(4, 2) << std::endl;
    std::cout << f3(4, 2) << std::endl;
    std::cout << f4(4, 2) << std::endl;
}

运行结果:

代码语言:javascript
复制
6
2
0
8

3.C++代码样例 Demo_1:

代码语言:javascript
复制

#include <functional>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void execute(const vector<function<void()>>& fs)
{
    for (auto& f : fs)
        f();
}
void plain_old_func()
{
    cout << "I'm an old plain function" << endl;
}
class functor
{
public:
    void operator()() const
    {
        cout << "I'm a functor" << endl;
    }
};
int main()
{
    vector<function<void()>> x;
    x.push_back(plain_old_func);
    functor functor_instance;
    x.push_back(functor_instance);
    x.push_back([]()
        {
            cout << "I'm a lambda expression" << endl;
        });
    execute(x);
}

运行结果:

代码语言:javascript
复制
I'm an old plain function
I'm a functor
I'm a lambda expression

Demo_2:

代码语言:javascript
复制
#include <iostream>   
#include <functional>   
int main() {
    // an array of functions:
    std::function<int(int, int)> fn[] = {
        std::plus<int>(),
        std::minus<int>(),
        std::multiplies<int>()
    };
    for (auto& x : fn) {
        std::cout << x(10, 5) << '\n';
    }
    return 0;
}

运行结果:

代码语言:javascript
复制
15
5
50

*补充:头文件functional在C++17标准中引入了std::invoke。 invoke可以不需要经过初始化操作,直接进行调用操作。 std::invoke具体使用方式参考如下代码:

代码语言:javascript
复制

#include <iostream>
#include <functional>
using namespace std;
void globalFunction()
{
    cout << "globalFunction ..." << endl;
}
class MyClass
{
public:
    void memberFunction(int data)
    {
        std::cout << "MyClass memberFunction ..." << std::endl;
    }
    static void staticFunction(int data)
    {
        std::cout << "MyClass staticFunction ..." << std::endl;
    }
};
int main()
{
    MyClass obj;
    std::invoke(&MyClass::memberFunction, obj, 100);
    std::invoke(&MyClass::staticFunction, 200);
    std::invoke(globalFunction);
    return 0;
}

运行结果:

代码语言:javascript
复制
MyClass memberFunction ...
MyClass staticFunction ...
globalFunction ...

三,参考阅读 《Beginning C++17, 5th Edition》 《C++ Primer Plus, 6th Edition》 《The C++ Standard Library, Second Edition》 《C++新经典》 C/C++开发基础——函数指针&回调函数 https://www.oreilly.com/library/view/mastering- c-programming/ https://oopscenities.net/2012/02/24/c11- stdfunction-and-stdbind/

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-02-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员与背包客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 二,标准库中的std::function模板
    • 1.std::function简介
      • 2.std::function具体用法
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档