当前位置:   article > 正文

C++:使用std::bind和形参包实现“万能函数指针”_c++ 创建万能函数指针

c++ 创建万能函数指针

这里的万能函数指针指的是返回值、参数个数和类型都任意的函数指针,可以用于某些高度抽象的函数调用场景。例如,对于一个树的结点,我们希望可以递归地调用它自己和它的所有子结点的某个函数,用一般的函数指针实现这个需求就是:

class TreeNode {
	public:
		void handle(void (TreeNode ::*handleFunction)(int), int para) {
		    (this->*handleFunction)(para);
		    for (auto c : m_children) {
		        (c->*handleFunction)(para);
	    }
	private:
		std::list<TreeNode> m_children;
		void handlePrint(int para) {
        	std::cout << para<< std::endl;
    	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这么写的问题在于一般的函数指针的返回值和参数类型必须是确定的,如果需要调用不同形式的函数,就要写多个重载函数。当然,模板能解决部分问题,但是也不是很方便。而如果参数的个数也不确定,只使用模板也没用。针对这两个问题,我们使用std::bind形参包就可以完美解决。

std::bind配合std::function是C++11针对函数指针的一种替代方案,而形参包则是针对可变参数(不定参数)的替代方案,功能更强大并且更好用。

先来看下面这段代码,我们定义了一个Object类,并且定义了一个可以调用其他 形式为 void (*)(int, int)的成员函数 的handle函数,在main函数里面就可以利用handle来调用Object::handlePrint。

class Object {
  public:
    void handle(void (Object::*handleFunction)(int, int), int para1, int para2) {
        (this->*handleFunction)(para1, para2);
    }
    void handlePrint(int para1, int para2) {
        std::cout << para1 << ' ' << para2 << std::endl;
    }
};
int main() {
    Object object;
    object.handle(&Object::handlePrint, 100, 200);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

如果需要让handle函数具备调用任意形式的成员函数的功能,那么就可以把实现修改为下面这样:

class Object {
  public:
    template <typename Returns = void, typename _Fx, typename... Args>
    Returns handle(_Fx&& _Func, Args... args) {
        auto handleFunction = std::bind(_Func, this, args...);
        return handleFunction();
    }
    void handlePrint(int para1, int para2) {
        std::cout << para1 << ' ' << para2 << std::endl;
    }
};
int main() {
    Object object;
    object.handle(&Object::handlePrint, 100, 200);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

函数的第一个参数_Func参照了std::bind源代码中的写法,代表任意一种(或者说未知类型的)函数,这里利用了C++的模板类型推导,让_Func的类型_Fx可以在编译时针对具体调用handle时的语句进行推导,达到一种“任意”的效果。&&代表万能引用,不熟悉模板推导和万能引用的朋友可以去阅读一下其他博主对C++新特新的讲解,这里不赘述了。函数的第二个参数args是参数包,不熟悉同样可以去查查相关资料,作用和可变参数类似。
函数的第一条语句使用std::bind把_Fucn绑定为一个std::function类型的handleFunction变量上,同时每次调用时都会自动为其传参args。最后调用handleFunction即可,注意这里的括号里就不要写args了,因为在前一句std::bind中已经绑定过了。

最后贴上一段完整的测试代码,可以看到handle函数确实能够对不同的函数形式均适用。如果需要调用的函数不是成员函数,需要修改的地方和一般的函数指针一样,不传this指针并且在调用时不加Object类限定符就行了。

#include <functional>
#include <iostream>

bool handlePositive(int num) {
    return num > 0;
}

template <typename Returns = void, typename _Fx, typename... Args>
Returns handle(_Fx&& _Func, Args... args) {
    auto handleFunction = std::bind(_Func, args...);
    return handleFunction();
}

class Object {
  public:
    template <typename Returns = void, typename _Fx, typename... Args>
    Returns handle(_Fx&& _Func, Args... args) {
        auto handleFunction = std::bind(_Func, this, args...);
        return handleFunction();
    }
    
    bool handlePositive(int num) {
        return num > 0;
    }

    void handlePrint(int para1, int para2) {
        std::cout << para1 << ' ' << para2 << std::endl;
    }
    
    std::list<int> handleDelete(std::list<int> list, int target) {
        list.remove(target);
        return list;
    }
};

int main() {
    Object object;

    std::cout << handle<bool>(handlePositive, 100) << std::endl;
    object.handle(&Object::handlePrint, 100, 200);
    auto returns = object.handle<std::list<int>>(&Object::handleDelete, std::list<int>{3, 2, 5, 1, 4}, 5);
    for (auto value : returns)
        std::cout << value << ' ';
    std::cout << std::endl;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/576985
推荐阅读
相关标签
  

闽ICP备14008679号