C++11的functional模块介绍和使用案例

 更新时间:2024年02月19日 10:55:44   作者:老狼IT工作室  
functional模块是C++ 11提供了一组函数对象和算法,用于增强C++的函数式编程能力,本文主要介绍了C++11的functional模块介绍和使用案例,具有一定的参考价值,感兴趣的可以了解一下

functional模块介绍

functional模块是C++ 11提供了一组函数对象和算法,用于增强C++的函数式编程能力。该模块中的函数对象和算法可以大大简化代码,并提供了一些有用的工具,例如函数适配器和函数对象的组合。

functional模块中的函数对象包括:

  • plus:加法函数对象,用于将两个参数相加。
  • minus:减法函数对象,用于将第一个参数减去第二个参数。
  • multiplies:乘法函数对象,用于将两个参数相乘。
  • divides:除法函数对象,用于将第一个参数除以第二个参数。
  • modulus:取模函数对象,用于返回第一个参数除以第二个参数的余数。
  • negate:取反函数对象,将参数取反。

functional模块中的算法包括:

  • bind:将一个函数对象和一些参数绑定在一起,生成一个新的函数对象。
  • mem_fn:将一个成员函数包装成函数对象。
  • not1:对一个函数对象进行逻辑非运算。
  • ref:将一个对象包装成一个引用包装器。
  • cref:将一个对象包装成一个const引用包装器。

使用案例

案例一

#include <iostream>
#include <functional>

int main() {
    std::plus<int> plusFunc;
    
    int result = plusFunc(1, 2);  // 将1和2相加,返回3
    
    std::cout << result << std::endl;
    
    return 0;
}

在上面的例子中,我们创建了一个std::plus<int>的实例plusFunc,该实例可以用于将两个整数相加。然后,我们调用plusFunc函数对象,传入参数1和2,并将返回的结果赋值给result变量。最后,我们将结果输出到控制台,得到的输出结果是3。

使用std::plus函数对象的好处是,它可以与其他函数对象和算法结合使用,例如使用std::transform算法对一个容器中的元素进行相加操作:

#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> nums {1, 2, 3, 4, 5};
    std::vector<int> result(nums.size());
    
    std::transform(nums.begin(), nums.end(), nums.begin(), std::negate<int>());
    std::transform(nums.begin(), nums.end(), result.begin(), std::bind(std::plus<int>(), std::placeholders::_1, 2));
    
    for (int num : result) {
        std::cout << num << " ";
    }
    
    return 0;
}

在上面的例子中,我们首先使用std::transform算法和std::negate函数对象对nums容器中的元素进行取反操作。然后,使用std::transform算法和std::bind函数将nums中的每个元素与2相加,并将结果存储在result容器中。最后,我们遍历result容器并输出每个元素的值。输出结果为-1 0 1 2 3,表示nums中的每个元素都加上了2。

这个例子展示了std::plus函数对象的灵活性,它可以与其他函数对象和算法结合使用,简化了代码,并提供了更好的可读性和可维护性。

案例二

#include <iostream>
#include <functional>

int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

int main() {
    std::function<int(int, int)> func1 = add;
    std::function<int(int, int)> func2 = std::bind(subtract, std::placeholders::_2, std::placeholders::_1);
    
    int result1 = func1(1, 2);  // 调用add函数,返回3
    int result2 = func2(2, 1);  // 调用subtract函数,返回1
    
    std::cout << result1 << std::endl;
    std::cout << result2 << std::endl;
    
    return 0;
}

在上面的例子中,我们定义了两个函数add和subtract,并使用std::function将它们包装成函数对象func1和func2。然后,我们可以像调用普通函数一样使用这些函数对象,通过调用func1和func2来执行对应的函数。输出结果分别为3和1。

在这个例子中,我们使用了bind函数将subtract函数的两个参数绑定在一起,然后通过调整参数的顺序来实现减法运算。这是functional模块中的一个常见用法,可以用来生成新的函数对象。

案例三

#include <iostream>
#include <functional>

class MyClass {
public:
    void printMessage(const std::string& message) {
        std::cout << message << std::endl;
    }
};

int main() {
    MyClass obj;
    auto printFunc = std::mem_fn(&MyClass::printMessage);
    
    printFunc(obj, "Hello, world!");  // 调用obj对象的printMessage函数,并传入参数"Hello, world!"
    
    return 0;
}

在上面的例子中,我们定义了一个名为MyClass的类,该类具有一个成员函数printMessage,用于输出一条消息。然后,我们创建了一个MyClass类型的对象obj,并使用std::mem_fn将printMessage函数转化为一个函数对象printFunc。最后,我们调用printFunc函数对象,传入obj对象和字符串参数"Hello, world!",从而调用了obj对象的printMessage函数并输出了消息。

使用std::mem_fn函数对象的好处是,它允许我们以通用的方式处理成员函数指针和成员函数对象,可以与其他函数对象和算法结合使用。例如,我们可以通过std::transform算法将一个容器中的每个元素调用成员函数并获取结果:

#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>

class MyClass {
public:
    int multiply(int x, int y) {
        return x * y;
    }
};

int main() {
    std::vector<int> nums {1, 2, 3, 4, 5};
    std::vector<int> result(nums.size());
    
    MyClass obj;
    auto multiplyFunc = std::mem_fn(&MyClass::multiply);
    
    std::transform(nums.begin(), nums.end(), result.begin(), std::bind(multiplyFunc, &obj, std::placeholders::_1, 2));
    
    for (int num : result) {
        std::cout << num << " ";
    }
    
    return 0;
}

在上面的例子中,我们定义了一个名为MyClass的类,该类具有一个成员函数multiply,用于计算两个整数的乘积。然后,我们创建了一个MyClass类型的对象obj,并使用std::mem_fn将multiply函数转化为一个函数对象multiplyFunc。最后,我们使用std::transform算法和std::bind函数将nums容器中的每个元素和数字2传入multiplyFunc函数对象中进行计算,并将结果存储在result容器中。最后,我们遍历result容器并输出每个元素的值。输出结果为2 4 6 8 10,表示nums中的每个元素都乘以了2。

这个例子展示了std::mem_fn函数对象的灵活性,它允许我们处理成员函数指针和成员函数对象,并与其他函数对象和算法结合使用,简化了代码,并提供了更好的可读性和可维护性。

案例四

#include <iostream>
#include <functional>

void updateValue(int& value) {
    value += 10;
}

int main() {
    int num = 5;
    
    std::cout << "Before update: " << num << std::endl;
    
    std::function<void()> updateFunc = std::bind(updateValue, std::ref(num));
    updateFunc();
    
    std::cout << "After update: " << num << std::endl;
    
    return 0;
}

在上面的例子中,我们定义了一个名为updateValue的函数,该函数接受一个引用参数,并将其值增加10。然后,我们创建了一个名为num的整数变量,初始值为5。接下来,我们使用std::ref函数模板将num对象转化为一个引用包装器,并通过std::bind函数将updateValue函数与引用包装器绑定到一起,创建一个函数对象updateFunc。最后,我们调用updateFunc函数对象,从而实际调用了updateValue函数,并传递了num对象的引用作为参数。输出结果为:

Before update: 5
After update: 15

可以看到,通过使用std::ref函数模板,我们可以在函数调用中传递对象的引用,从而实现对对象的修改。

案例五

#include <iostream>
#include <functional>

void printValue(const int& value) {
    std::cout << "Value: " << value << std::endl;
}

int main() {
    int num = 10;

    std::function<void()> printFunc = std::bind(printValue, std::cref(num));
    printFunc();

    return 0;
}

在上面的例子中,我们定义了一个名为printValue的函数,该函数接受一个常量引用参数,并打印该值。然后,我们创建了一个名为num的整数变量,初始值为10。接下来,我们使用std::cref函数模板将num对象转化为一个常量引用包装器,并通过std::bind函数将printValue函数与常量引用包装器绑定到一起,创建一个函数对象printFunc。最后,我们调用printFunc函数对象,从而实际调用了printValue函数,并传递了num对象的常量引用作为参数。输出结果为:

Value: 10

可以看到,通过使用std::cref函数模板,我们可以在函数调用中传递对象的常量引用,从而实现对对象的只读访问。

案例六

#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>

bool isOdd(int num) {
    return num % 2 != 0;
}

int main() {
    std::vector<int> nums {1, 2, 3, 4, 5};
    
    std::vector<int> evenNums;
    std::copy_if(nums.begin(), nums.end(), std::back_inserter(evenNums), std::not1(std::ptr_fun(isOdd)));
    
    for (int num : evenNums) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

在上面的例子中,我们定义了一个名为isOdd的谓词函数,该函数接受一个整数参数,并判断该整数是否为奇数。然后,我们创建了一个整数类型的vector容器nums,并使用std::copy_if算法和std::not1函数模板将nums容器中的所有偶数元素复制到另一个vector容器evenNums中。在调用std::copy_if算法时,我们使用std::not1函数模板将isOdd谓词函数进行否定操作,从而实现对偶数元素的筛选。最后,我们遍历evenNums容器并输出其中的所有元素。输出结果为:

2 4

这个例子展示了std::not1函数模板的用途,可以对谓词函数进行否定操作,从而实现相反的逻辑判断。在实际开发中,std::not1函数模板可以用于各种需要对谓词函数进行逻辑反操作的场景,例如在STL算法中对元素进行筛选、排序或处理等操作。

到此这篇关于C++11的functional模块介绍和使用案例的文章就介绍到这了,更多相关C++11 functional模块内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++抽奖程序实现方法

    C++抽奖程序实现方法

    这篇文章主要介绍了C++抽奖程序实现方法,实例分析了C++随机数的生成技巧与抽奖程序的实现方法,需要的朋友可以参考下
    2015-07-07
  • C++设计模式之桥接模式(Bridge)

    C++设计模式之桥接模式(Bridge)

    这篇文章主要为大家详细介绍了C++设计模式之桥接模式Bridge,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-04-04
  • C++ 项目引入lib和dll的区别与使用实战

    C++ 项目引入lib和dll的区别与使用实战

    静态链接库与动态链接库都是共享代码的方式,本文主要介绍了C++项目引入lib和dll的区别与使用实战,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02
  • C语言冷门知识之你可能没听过的柔性数组

    C语言冷门知识之你可能没听过的柔性数组

    柔性数组(Flexible Array)是引入的一个新特性,它允许你在定义结构体时创建一个空数组,而这个数组的大小可以在程序运行的过程中根据你的需求进行更改特别注意的一点是:这个空数组必须声明为结构体的最后一个成员,并且还要求这样的结构体至少包含一个其他类型的成员
    2021-10-10
  • C++子类父类成员函数的覆盖和隐藏实例详解

    C++子类父类成员函数的覆盖和隐藏实例详解

    这篇文章主要介绍了C++子类父类成员函数的覆盖和隐藏实例详解的相关资料,需要的朋友可以参考下
    2017-06-06
  • 一篇文章让你彻底明白c++11增加的变参数模板

    一篇文章让你彻底明白c++11增加的变参数模板

    C++11的新特性--可变模版参数(variadic templates)是C++11新增的最强大的特性之一,它对参数进行了高度泛化,它能表示0到任意个数、任意类型的参数,这篇文章主要给大家详细介绍了关于c++11增加的变参数模板的相关资料,需要的朋友可以参考下
    2021-08-08
  • C语言报错Use of Uninitialized Variable的原因及解决方案

    C语言报错Use of Uninitialized Variable的原因及解决方案

    Use of Uninitialized Variable是C语言中常见且危险的错误之一,它通常在程序试图使用一个未初始化的变量时发生,本文将详细介绍Use of Uninitialized Variable的产生原因,提供多种解决方案,并通过实例代码演示如何有效避免和解决此类错误,需要的朋友可以参考下
    2024-06-06
  • 判断机器大小端的两种实现方法

    判断机器大小端的两种实现方法

    第一种方法,思路:利用指针的强制类型转换。第二种方法,思路:利用共用体所有数据都从同一地址开始存储。
    2013-03-03
  • C++中 STL list详解及简单实例

    C++中 STL list详解及简单实例

    这篇文章主要介绍了C++中 STL list详解及简单实例的相关资料,需要的朋友可以参考下
    2017-04-04
  • 二叉树遍历 非递归 C++实现代码

    二叉树遍历 非递归 C++实现代码

    对于二叉树,有前序、中序以及后序三种遍历方法。因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁。而对于树的遍历若采用非递归的方法,就要采用栈去模拟实现
    2013-09-09

最新评论