[6 函数子类及函数] 41. 理解ptr_fun、mem_fun和mem_fun_ref的来由

这些函数的主要任务是解决C++语法中的一个语法不一致问题。

如果有一个函数f和一个对象x,希望在对象x上调用函数f,为了执行这个调用,C++提供了3种不同的语法:

// 语法#1:f是一个非成员函数
f(x);
// 语法#2:f是一个成员函数,且x是一个对象或对象的引用
x.f();
// 语法#3:f是成员函数,且p是一个指向对象x的指针
p->f();

假如有一个测试函数test:

// 测试函数test
void test(Widget& w);
vector<Widget> vw;
...
// 调用#1,可通过编译
for_each(vw.begin(), vw.end(), test);

假如test是Widget的成员函数:

class Widget {
public:
    ...
    void test();
    ...
};
// 调用#2,不能通过编译
for_each(vw.begin(), vw.end(), &Widget::test);

假如有一个存放Widget*指针的容器:

list<Widget*> lpw;
// 调用#3,不能通过编译
for_each(lpw.begin(), lpw.end(), &Widget::test);

(1)一个非成员函数(2)一个对象和一个成员函数(3)一个对象指针和一个成员函数,难道我们需要3个版本的for_each实现么?然而,现实是,我们只有一个for_each算法:

template<typename InputIterator, typename Function>
Function for_each(InputIterator begin, InputIterator end, Function f)
{
    while (begin != end) f(*begin++);
}

可以看出,STL中的惯例是:函数或函数对象在被调用时,总是使用非成员函数的语法形式。

所以mem_fun和mem_fun_ref之所以存在的原因是它们被用来调整#语法2,#语法3的成员函数,使之能够通过#语法1被调用。来看下转换原理,mem_fun、mem_fun_ref是函数模板:

//mem_fun声明针对不带参数的非const成员函数
//C是类,R是指向的成员函数的返回类型
template<typename R, typename C>
mem_fun_t<R,C> mem_fun( R(C::*pmf)() );

mem_fun带一个指向某个成员函数的指针参数pmf,并且返回一个mem_func_t类型的对象。mem_func_t是一个函数子类,它拥有该成员函数的指针,并提供了opeartor()函数,在operator()中调用了通过参数传递进来的对象上的该成员函数。(相当于将类的一个成员函数转换为一个函数子类了)

list<Widget*> lpw;
...
//现在可以通过编译了
for_each(lpw.begin(), lpw.end(), mem_fun(&Widget::test));

mem_fun_ref与mem_fun类似,它将语法#2转换为语法#1,并产生一个类型为mem_fun_ref_t的配接器对象。(mem表示member,成员函数的意思)

ptr_fun使用的策略是,出现编译错误时使用,作用是提供必要的类型定义。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`std::ptr_fun`是C++标准库中的一个函数模板,位于头文件`<functional>`中。它可以将普通函数指针或函数对象转换为函数适配器,以便在算法中使用。 `std::ptr_fun`的定义如下: ```cpp template <typename Arg, typename Result> std::pointer_to_unary_function<Arg, Result> ptr_fun(Result (*f)(Arg)); ``` 参数`f`是一个普通函数指针,它指向一个接受类型为`Arg`的参数并返回类型为`Result`的函数。 `std::ptr_fun`函数模板返回一个`std::pointer_to_unary_function`类型的函数适配器对象,该对象可以将其参数应用于传入的函数指针。 以下是一个简单的示例,展示了如何使用`std::ptr_fun`将普通函数指针转换为函数适配器,并在算法中使用它: ```cpp #include <iostream> #include <algorithm> #include <vector> #include <functional> // 普通函数 bool isEven(int num) { return num % 2 == 0; } int main() { std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // 将普通函数指针转换为函数适配器 std::function<bool(int)> isEvenAdapter = std::ptr_fun<int, bool>(isEven); // 使用函数适配器进行判断 auto it = std::find_if(numbers.begin(), numbers.end(), isEvenAdapter); if (it != numbers.end()) { std::cout << "找到了第一个偶数:" << *it << std::endl; } else { std::cout << "未找到偶数" << std::endl; } return 0; } ``` 输出结果: ``` 找到了第一个偶数:2 ``` 在上面的示例中,我们定义了一个名为`isEven`的普通函数,用于判断一个整数是否为偶数。然后,我们使用`std::ptr_fun`将普通函数指针`isEven`转换为函数适配器`isEvenAdapter`。最后,我们使用函数适配器`isEvenAdapter`在容器`numbers`中查找第一个满足条件的元素。最终找到了第一个偶数2并输出。 需要注意的是,C++11之后,可以直接使用lambda表达式或者函数对象代替`std::ptr_fun`来实现相同的功能,更加简洁方便。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值