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

C++中使用函数作为回调时如何避免额外存储开销?

解决方案

C++20及以上版本可通过非类型模板参数(NTTP)+ 自定义CTAD推导指引实现需求,无需使用宏,无需用户修改现有调用写法,同时还能保留运行期函数指针传入的合法性。

修改后的库代码实现

// ***** 库代码 ***** 
#include <concepts>
#include <utility>

// 辅助空类型:将编译期函数地址作为模板参数存储,实例无任何存储开销
template<auto Func>
struct function_constant {
    constexpr auto operator()(auto&&... args) const 
        noexcept(noexcept(Func(std::forward<decltype(args)>(args)...)))
        -> decltype(Func(std::forward<decltype(args)>(args)...))
    {
        return Func(std::forward<decltype(args)>(args)...);
    }
};

template <std::invocable CbT>
struct delegated {
    explicit constexpr delegated(CbT cb) : cb_(std::move(cb)) {}

 private:
    [[no_unique_address]] CbT cb_;
};

// 通用CTAD推导指引:匹配所有编译期可知的函数指针,自动包装为function_constant
template<class R, class... Args, R(*Func)(Args...)>
delegated(R(*)(Args...)) -> delegated<function_constant<Func>>;

运行效果

原有用户代码无需任何修改,重新编译后输出如下:

func: 1        <----- 已消除存储开销,符合预期
func_ptr: 8    <----- 运行期函数指针保持原有逻辑,结果合理
lambda: 1      <----- 无捕获lambda效果不变
functor: 1     <----- 自定义仿函数效果不变

实现原理

  • 当用户调用delegated{func}时,函数名func退化为编译期可知的函数指针常量,触发自定义CTAD推导指引,自动将函数地址封装为function_constant空类型,实例无需存储任何数据,因此sizeof为1。
  • 当用户传入运行期可变的函数指针变量时,由于其值无法在编译期确定,不会匹配到上述推导指引,会走原有通用模板逻辑存储指针,完全符合设计预期。
  • 无捕获lambda、自定义仿函数等原有调用逻辑完全不受影响,无兼容性问题。

如果需要兼容C17及更早版本,才需要借助宏来自动生成包装lambda的代码,只要目标编译环境支持C20,上述方案即可完全满足需求。

内容的提问来源于stack exchange,提问作者user4442671

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 05:54:00