C++如何存储std::bind生成的可调用对象解决编译错误
问题根因
编译错误由类型不匹配直接导致:
- 类成员
function被声明为裸函数指针void (*)(),该类型仅能接收无入参、返回void的普通自由函数地址 std::bind的返回值是标准库内部定义的匿名可调用对象,不属于裸函数指针类型,不存在到void (*)()的隐式转换规则,因此赋值操作会直接报错。
即使传入无参函数f1,std::bind(f1)返回的依然是bind包装对象而非裸函数指针,因此第一个call调用同样会触发编译错误。
修复方案
- 将裸函数指针成员替换为
std::function<void()>:这是标准库提供的类型擦除可调用包装器,可以存储任意符合void()调用签名的可调用对象,包括普通函数、bind返回值、lambda表达式、自定义仿函数等,从根本上解决类型转换问题。 call模板方法中对传入的函数和参数使用完美转发,减少不必要的参数拷贝,同时避免参数引用绑定错误。相比std::bind,更推荐使用lambda捕获参数包装任务,语义更清晰,也能规避std::bind的部分历史设计缺陷。
修正后可正常编译运行的最小代码如下:
#include <chrono> #include <functional> #include <iostream> #include <thread> #include <utility> class Context { private: std::thread thread; bool running; void run() { while (running) { if (function != nullptr) { function(); function = nullptr; } } } // 替换裸函数指针为std::function可调用包装器 std::function<void()> function; public: Context() : running(true) { thread = std::thread(&Context::run, this); } ~Context() { running = false; thread.join(); } template <typename T, typename... Args> void call(T&& func, Args&&... args) { // 推荐lambda包装方式,可读性更强 function = [f = std::forward<T>(func), ...cap_args = std::forward<Args>(args)]() mutable { f(cap_args...); }; // 若偏好std::bind写法,可替换为下面这行 // function = std::bind(std::forward<T>(func), std::forward<Args>(args)...); } }; // 测试函数 void f1() { std::cout << "f1" << std::endl; } void f2(int a) { std::cout << "f2(" << a << ")" << std::endl; } void f3(int a, int b) { std::cout << "f3(" << a << ", " << b << ")" << std::endl; } int main() { Context context; context.call(f1); context.call(f2, 1); context.call(f3, 1, 2); // 测试用例加延时等待任务执行完成,实际生产环境用条件变量等机制同步即可 std::this_thread::sleep_for(std::chrono::seconds(1)); return 0; }
说明:上述代码仅修复编译错误,你提到的线程互斥、任务队列、线程阻塞唤醒、安全退出等生产环境必需逻辑,按你原有设计补充即可。
内容的提问来源于stack exchange,提问作者LiteApplication
相关产品推荐
相关产品推荐

