C++函数适配器

先弄清几个概念,什么叫一元函数,二元函数

1.    一元函数一个参数
2.
二元函数 两个参数
3. 一元谓词 一个参数,返回类型为bool型
4. 二元谓词 两个参数,返回类型为bool型

函数适配器是用来让一个函数对象表现出另外一种类型的函数对象的特征。因为,许多情况下,我们所持有的函数对象或普通函数的参数个数或是返回值类型并不是我们想要的,这时候就需要函数适配器来为我们的函数进行适配

 

C++中有三类适配器,分别是容器适配器,迭代器适配器和函数适配器,这里主要介绍函数适配器。
函数适配器用于特化和扩展一元二元函数对象,函数适配器主要有以下两类:
1 绑定器

该类适配器用于将二元函数适配成一元函数

 将二元函数的一个参数绑定到一个特定的值上,将二元函数对象转换成一元函数对象。
  绑定器适配器有两种:bind1st bind2nd。每个绑定器接受一个函数对象和一个值
  bind1st将给定值绑定到二元函数对象的第一个实参
  bind2nd将给定值绑定到二元函数对象的第二个实参
  例子:

先看下count_if的普通用法

count_if:  利用输入的函数,对标志范围内的元素进行比较操作,返回结果为true的个数。例如:vecInt是用vector<int>声明的容器,已包含1,3,5,7,9元素,现要求求出大于等于3的元素个数

bool GreaterThree(int iNum)
{
if(iNum>=3)
{
return true;
}
else
{
return false;
}
}
int iCount = count_if(vecIntA.begin(),vecIntA.end(), GreaterThree);
//这里要求GreaterThree的函数参数必须是一个
//此时iCount == 4

 count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10)); 
// less_equal<int>()函数是两个参数,怎样让他变成一个参数呢?
less_equal是STL为我们提供的一个函数对象,它有两个参数,其作用是比较第一个参数值是否<=第二个参数值。但是count_if要求我们第三个参数必须是一个一元谓词(就是只有一个参数),所以我们用bind2nd对该函数对象进行适配,将10绑定到该函数对象的第二个参数上。
(意思就是说less_equal<int>( _Left, _Right)这个函数只要他的第二个参数,第一个参数忽略)
现在cont_if执行的功能实际上就变成了查找给定序列中值<=10的元素的个数

取反器 将函数对象的结果真值求反
  
取反器有两种:not1not2
  not1
是对一元函数对象求反的取反器,传递给函数对象的只有一个参数,则要使用这个not1
  not2
是对二元函数对象求反的取反器
  
例子
 int* where=find_if(&array[0],&array[100],not1(bind2nd(breater<int>(),200)))

推荐一个很好的判断传参的方法:先写一个类,重载()算符,并接受传递进来的参数,判断后再返回真假
例子:

#include <functional>
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <cassert>
#define ASSERT assert
using namespace std;
class Rand:public binary_function<int, int, int>
{
public:
    Rand()
    { srand((unsigned int)time(NULL)); }
    int operator()(int minval, int maxval) const
    {
        ASSERT(maxval>minval);
        ASSERT(minval>=0);
        ASSERT(maxval<=RAND_MAX);
        return (rand()%(maxval-minval)) + minval;
    }
};
int main()
{
    cout<<Rand()(1,5)<<endl; //[1,5)
    cout<<bind1st(Rand(),20)(30)<<endl;
    return 0;
}


### C++函数对象适配器的使用方法 #### 继承 `binary_function` 类型并重载调用操作符 为了创建一个可以被适配器使用的自定义函数对象,通常需要继承标准库中的辅助基类之一。对于接受两个参数的函数对象来说,应该继承 `std::binary_function<Arg1, Arg2, Result>`[^1]。 ```cpp struct Myfunc1 : public std::binary_function<int, int, void> { void operator()(int v1, int v2) const { std::cout << v1 + v2 << std::endl; } }; ``` 这段代码展示了如何定义一个名为 `Myfunc1` 的结构体作为二元函数对象,并实现了加法运算的功能。 #### 使用绑定器 `bind2nd` 当希望固定某个参数值时,可以利用绑定器如 `std::bind2nd` 来部分应用这些参数。这使得能够将一个多参函数转换为少参版本,在此例子中就是把双目运算变成单目的形式[^2]。 ```cpp void test26() { std::vector<int> v{1, 2, 3}; // 将第二个参数设置为固定的数值100并与第一个参数相加打印出来 std::for_each(v.begin(), v.end(), std::bind2nd(Myfunc1(), 100)); } ``` 这里展示了一个简单的测试案例,通过遍历整数向量并将每个元素与常量100一起传递给之前定义好的 `Myfunc1` 函数对象来进行处理。 #### 包含必要的头文件和支持命名空间 在实际编写程序前还需要确保包含了适当的标准库支持以及声明了正确的命名空间。特别是涉及到泛函编程组件的时候,往往需要用到 `<functional>` 头文件: ```cpp #include <iostream> #include <vector> #include <algorithm> #include <functional> // 如果是C++11及以上,则不需要显式引入tr1命名空间下的占位符 using namespace std; ``` 以上介绍了基本概念及其具体实践方式;值得注意的是现代C++提供了更灵活通用的方法比如 `std::bind()` 和 lambda 表达式的组合来达到相同的效果[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值