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

如何用std::bind绑定内部调用std::bind的函数?

问题描述

使用C++17编译时,尝试用NoParameterBinding封装BindRequest::bindOnce时编译失败,报错无法转换为std::function<void()>。

已实现两种通用函数绑定方式:

  • NoParameterBinding:绑定函数与所有参数,生成可无参调用的std::function<void()>,运行正常;
  • SingleParameterBinding:用std::placeholders::_1保留第一个参数,绑定其余参数,生成std::function<void(long)>,运行正常;
  • BindRequest::bindOnce可转发参数给SingleParameterBinding::bind,运行正常;但BindRequest::bindTwice尝试将bindOnce作为参数传给NoParameterBinding::bind时编译报错。

编译器错误信息:

forwarding.cpp:10:38: error: conversion from ‘std::_Bind_helper<false, void (&)(void (&)(const long int&, const double&), double&&), void (&)(const long int&, const double&), double>::type’ to non-scalar type ‘NoParameterBinding::Task’ {aka ‘std::function<void()>’} requested

相关代码:

#include<functional>

struct NoParameterBinding
{
        using Task = std::function<void()>;

        template<typename FuncType, typename... Args>
            static void bind(FuncType&& func, Args&&... args)
            {
                Task task = std::bind(std::forward<FuncType>(func), std::forward<Args>(args)...);
            }
};

struct SingleParameterBinding
{
        using CallbackType = std::function<void(long)>;

        template<typename FuncType, typename... Args>
            static void bind(FuncType&& callbackFunc, Args&&... args)
            {
                CallbackType callback = std::bind(std::forward<FuncType>(callbackFunc), std::placeholders::_1, std::forward<Args>(args)...);
            }

};

struct BindRequest
{
        using CallbackType = SingleParameterBinding::CallbackType;

        template<typename CallbackFuncType, typename... CallbackArgs>
            static void bindOnce(CallbackFuncType&& callback, CallbackArgs&&... callbackArgs)
            {
                SingleParameterBinding::bind(std::forward<CallbackFuncType>(callback), std::forward<CallbackArgs>(callbackArgs)...);
            }

        template<typename CallbackFuncType, typename... CallbackArgs>
            static void bindTwice(CallbackFuncType&& callback, CallbackArgs&&... callbackArgs)
            {
                NoParameterBinding::bind(BindRequest::bindOnce<CallbackFuncType, CallbackArgs...>, std::forward<CallbackFuncType>(callback), std::forward<CallbackArgs>(callbackArgs)...);
            }
};

void exampleCallback(const long& l, const double& d)
{
    return;
}

int main()
{
    NoParameterBinding::bind(exampleCallback,'a',9.9);
    SingleParameterBinding::bind(exampleCallback, 9.9);
    BindRequest::bindOnce(exampleCallback, 9.9);
    BindRequest::bindTwice(exampleCallback, 9.9); //Why freak out here?
    return 0;
}
问题分析与解决

问题核心在于std::bind处理模板函数的机制:当你传递BindRequest::bindOnce<CallbackFuncType, CallbackArgs...>给std::bind时,传递的是模板函数实例化后的函数引用,但bindOnce的参数包含右值引用(CallbackFuncType&&、CallbackArgs&&...),std::bind在转发这些参数时会触发引用折叠问题,最终生成的绑定对象签名与std::function<void()>不匹配,导致转换失败。

另外,std::bind对模板函数、重载函数的处理本身容易引发陷阱,更推荐用lambda替代,写法直观且能规避引用相关问题。

修改BindRequest::bindTwice的实现,用lambda封装bindOnce的调用:

template<typename CallbackFuncType, typename... CallbackArgs>
static void bindTwice(CallbackFuncType&& callback, CallbackArgs&&... callbackArgs)
{
    NoParameterBinding::bind(
        [
            cb = std::forward<CallbackFuncType>(callback),
            ... args = std::forward<CallbackArgs>(callbackArgs)
        ]() mutable {
            BindRequest::bindOnce(std::move(cb), std::move(args)...);
        }
    );
}

这个方案会创建一个无参lambda,内部调用bindOnce并传递绑定好的参数,lambda可以被正确转换为std::function<void()>,符合NoParameterBinding::Task的要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 04:25:11