You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

模板类非静态成员函数用作回调报错,如何解决?

非静态成员函数作为回调函数的解决方案

问题描述

尝试将模板类的非静态成员函数赋值为回调函数时遇到编译错误,错误信息如下:

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可以封装捕获上下文的可调用对象,比原始函数指针更灵活,步骤如下:

  1. 引入头文件并修改回调类型定义:
#include <functional>
using CallbackAfterWrite = std::function<void()>;
  1. 调整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;
};
  1. 为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;
};
  1. 在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特性,可以通过传递对象指针作为回调参数,间接调用非静态成员函数:

  1. 修改回调类型为带上下文参数的函数指针:
using CallbackAfterWrite = void (*)(void*);
  1. 调整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;
};
  1. 为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;
};
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 11:25:10