boost::thread传入模板回调触发invalid static_cast报错问题
问题描述
编写用于简化ROS环境下线程管理的工具类时,需要将采用boost库lambda表达式风格编写的ROS回调函数作为参数,传入线程处理对象TriggeredProcess类,初始实现代码如下:
#include <boost/function.hpp> #include <boost/thread.hpp> namespace alongside { class TriggeredProcess { public: template<typename Message> TriggeredProcess( const boost::function<void (Message const&)>& callback ) { boost::thread triggred_process( static_cast<void(*)( const boost::function<void (Message const&)>&s )>(&run), callback ); } private: template<typename Message> void run( const boost::function<void (Message const&)>& callback ) { //placeholder } }; } int main(int argc, char** argv) { /** * @brief 原本使用roscpp的std_msg::Bool类型,可替换为任意消息类型 * 此处为避免ROS依赖,使用基础bool类型复现相同错误 */ boost::function<void (const bool&)> callback = [&] (const bool& msg) { //placeholder }; alongside::TriggeredProcess a(callback); }
编译报错
编译时触发如下错误:
error: invalid static_cast from type ‘<unresolved overloaded function type>’ to type ‘void (*)(const boost::function<void(const bool&)>&)’ 14 | static_cast<void(*)( | ^~~~~~~~~~~~~~~~~~~~ 15 | const boost::function<void (Message const&)>&s | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 16 | )>(&run), | ~~~~~~~~
开发环境
Thread model: posix gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1)
问题根因
现有实现存在两个核心错误:
- 非静态成员函数无法转换为普通函数指针:
run是TriggeredProcess的非静态成员函数,其函数签名自带隐式this指针参数,类型为void (TriggeredProcess::*)(const boost::function<void(Message const&)>&),和static_cast目标的普通函数指针类型void (*)(const boost::function<void(Message const&)>&)完全不匹配。 - 未显式指定成员函数模板的实例化参数:
run是模板函数,直接取&run时编译器无法确定要实例化哪个版本的run,因此会报“未解析的重载函数类型”错误。
另外原实现还存在隐藏崩溃风险:boost::thread对象是构造函数内的局部变量,出构造函数作用域后会马上析构,若线程处于joinable状态,析构会直接触发std::terminate导致程序崩溃。
可行实现方案
方案1:将run改为静态成员函数
静态成员函数没有隐式this指针,可以正常转换为普通函数指针,同时显式指定模板实例参数即可通过编译,注意将线程对象存为类成员避免析构崩溃:
#include <boost/function.hpp> #include <boost/thread.hpp> namespace alongside { class TriggeredProcess { public: template<typename Message> TriggeredProcess( const boost::function<void (Message const&)>& callback ) { // 显式指定模板实例,静态成员可直接作为线程入口的可调用对象 triggered_process_ = boost::thread( &TriggeredProcess::run<Message>, callback ); } // 析构时等待线程退出,可根据业务需求改为detach ~TriggeredProcess() { if (triggered_process_.joinable()) { triggered_process_.join(); } } private: // 改为静态成员函数,无隐式this参数 template<typename Message> static void run( const boost::function<void (Message const&)>& callback ) { // 业务逻辑占位 } boost::thread triggered_process_; // 持有线程对象,避免局部变量析构崩溃 }; }
方案2:直接用lambda作为线程入口
不需要单独定义run成员函数,直接在构造函数内用lambda捕获回调参数编写线程逻辑,写法更简洁,完全不需要处理模板函数指针转换问题:
#include <boost/function.hpp> #include <boost/thread.hpp> namespace alongside { class TriggeredProcess { public: template<typename Message> TriggeredProcess( const boost::function<void (Message const&)>& callback ) { triggered_process_ = boost::thread([callback]() { // 直接在此处编写原run函数内的业务逻辑,可直接访问捕获的callback // 业务逻辑占位 }); } ~TriggeredProcess() { if (triggered_process_.joinable()) { triggered_process_.join(); } } private: boost::thread triggered_process_; }; }
内容的提问来源于stack exchange,提问作者Gabriel De Champeaux
相关产品推荐
相关产品推荐

