模板类非静态成员函数用作回调报错,如何解决?
非静态成员函数作为回调函数的解决方案
问题描述
尝试将模板类的非静态成员函数赋值为回调函数时遇到编译错误,错误信息如下:
main.cpp: In function ‘int main()’:
main.cpp:62:37: error: invalid use of non-static member function ‘void Class1::Callback() [with T = unsigned char]’
62 | pBuffer->SetWrCallback(pClass1->Callback);
| ~~~~~~~^
main.cpp:43:10: note: declared here
43 | void Callback()
| ^
由于回调函数需要访问类的非静态Buffer指针,无法将其设置为static,相关代码如下:
#include <iostream> using namespace std; using CallbackAfterWrite = void (*)(void); template<typename T> class Buffer { public: Buffer() {} ~Buffer() {} std::size_t size() { return 10; } void SetWrCallback(CallbackAfterWrite wrCallback) { mWrCallback = wrCallback; } private: CallbackAfterWrite mWrCallback; }; template<typename T> class Class1 { public: Class1() {} ~Class1() {} void Callback() { if(0 != mpBuffer->size()) { std::cout<< "Trigger callback" <<endl; } } private: Buffer<T> *mpBuffer; }; int main() { cout<<"Hello World"<<endl; Buffer<uint8_t>* pBuffer = new Buffer<uint8_t>; Class1<uint8_t>* pClass1 = new Class1<uint8_t>; pBuffer->SetWrCallback(pClass1->Callback); return 0; }
解决方案
方法1:使用std::function和Lambda表达式(C++11及以上)
std::function可以封装捕获上下文的可调用对象,比原始函数指针更灵活,步骤如下:
- 引入头文件并修改回调类型定义:
#include <functional> using CallbackAfterWrite = std::function<void()>;
- 调整
Buffer类的回调存储和触发逻辑:
template<typename T> class Buffer { public: Buffer() {} ~Buffer() {} std::size_t size() { return 10; } void SetWrCallback(CallbackAfterWrite wrCallback) { mWrCallback = std::move(wrCallback); } // 新增触发回调的方法(根据实际场景调用) void TriggerCallback() { if(mWrCallback) mWrCallback(); } private: CallbackAfterWrite mWrCallback; };
- 为
Class1添加Buffer指针的设置方法,并用Lambda绑定回调:
template<typename T> class Class1 { public: Class1() {} ~Class1() {} void Callback() { if(0 != mpBuffer->size()) { std::cout<< "Trigger callback" <<endl; } } // 新增设置Buffer指针的方法 void SetBuffer(Buffer<T>* pBuf) { mpBuffer = pBuf; } private: Buffer<T> *mpBuffer; };
- 在
main函数中完成绑定和测试:
int main() { cout<<"Hello World"<<endl; Buffer<uint8_t>* pBuffer = new Buffer<uint8_t>; Class1<uint8_t>* pClass1 = new Class1<uint8_t>; pClass1->SetBuffer(pBuffer); // 用Lambda捕获对象指针,绑定非静态成员函数 pBuffer->SetWrCallback([pClass1](){ pClass1->Callback(); }); pBuffer->TriggerCallback(); // 触发回调测试 // 释放内存 delete pClass1; delete pBuffer; return 0; }
方法2:使用成员函数指针+上下文指针(兼容旧C++标准)
如果无法使用C++11特性,可以通过传递对象指针作为回调参数,间接调用非静态成员函数:
- 修改回调类型为带上下文参数的函数指针:
using CallbackAfterWrite = void (*)(void*);
- 调整
Buffer类,同时存储回调函数和上下文指针:
template<typename T> class Buffer { public: Buffer() {} ~Buffer() {} std::size_t size() { return 10; } void SetWrCallback(CallbackAfterWrite wrCallback, void* context) { mWrCallback = wrCallback; mContext = context; } void TriggerCallback() { if(mWrCallback) mWrCallback(mContext); } private: CallbackAfterWrite mWrCallback; void* mContext; };
- 为
Class1添加静态包装函数,用于中转调用非静态成员函数:
template<typename T> class Class1 { public: Class1() {} ~Class1() {} void Callback() { if(0 != mpBuffer->size()) { std::cout<< "Trigger callback" <<endl; } } // 静态包装函数,将上下文指针转为类对象指针后调用成员函数 static void CallbackWrapper(void* context) { Class1<T>* pThis = static_cast<Class1<T>*>(context); pThis->Callback(); } void SetBuffer(Buffer<T>* pBuf) { mpBuffer = pBuf; } private: Buffer<T> *mpBuffer; };
- 在
main函数中设置回调:
int main() { cout<<"Hello World"<<endl; Buffer<uint8_t>* pBuffer = new Buffer<uint8_t>; Class1<uint8_t>* pClass1 = new Class1<uint8_t>; pClass1->SetBuffer(pBuffer); pBuffer->SetWrCallback(&Class1<uint8_t>::CallbackWrapper, pClass1); pBuffer->TriggerCallback(); delete pClass1; delete pBuffer; return 0; }
注意事项
- 方法1更简洁现代,优先在C++11及以上版本使用;方法2兼容旧标准,但代码相对繁琐。
- 必须确保回调触发时,绑定的对象指针仍然有效,避免悬空指针导致程序崩溃。
- 示例中的
TriggerCallback用于测试,实际场景中需根据Buffer的业务逻辑在合适时机调用回调。
内容的提问来源于stack exchange,提问作者karanbanthia
相关产品推荐
相关产品推荐

