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

正确使用std::function::target:实现Callable与std::function目标匹配函数

判断std::function是否指向特定Callable对象的实现方案

我来帮你解决这个问题——要实现一个能判断std::function的目标是否是传入的Callable对象的test函数,核心难点在于std::function对不同类型Callable的存储方式不一样,我们需要分情况处理函数指针和自定义仿对象。

完整实现代码

#include <type_traits>
#include <iostream>
#include <functional>

int foo(int) {return 0;}
int faz(int) {return 0;}

// 给仿对象添加默认的operator==,用于值比较
struct Callable {
    int operator()(int) {return 0;}
    bool operator==(const Callable&) const = default;
} bar, baz;

// 辅助模板:判断类型是否为函数指针
template<typename T>
struct is_function_pointer : std::is_pointer<T> {};

template<typename R, typename... Args>
struct is_function_pointer<R(*)(Args...)> : std::true_type {};

// 针对函数指针的重载
template<class FuncPtr, class F2>
std::enable_if_t<is_function_pointer<std::decay_t<FuncPtr>>::value, bool>
test(FuncPtr&& f1, std::function<F2> f2) {
    using PtrType = std::decay_t<FuncPtr>;
    // 获取std::function内部存储的函数指针的指针
    auto target_ptr = f2.template target<PtrType>();
    // 先检查target不为空(类型匹配),再比较指针值
    return target_ptr != nullptr && *target_ptr == f1;
}

// 针对自定义可调用对象的重载(非函数指针)
template<class CallableObj, class F2>
std::enable_if_t<!is_function_pointer<std::decay_t<CallableObj>>::value, bool>
test(CallableObj&& f1, std::function<F2> f2) {
    using ObjType = std::decay_t<CallableObj>;
    // 获取std::function内部存储的对象的指针
    auto target_ptr = f2.template target<ObjType>();
    // 检查类型匹配,再比较对象值(依赖operator==)
    return target_ptr != nullptr && *target_ptr == f1;
}

int main() {
    std::function<int(int)> f{foo};
    std::cout << std::boolalpha << test(foo, f) << std::endl; // 输出true
    std::cout << std::boolalpha << test(faz, f) << std::endl; // 输出false
    f = bar;
    std::cout << std::boolalpha << test(bar, f) << std::endl; // 输出true
    std::cout << std::boolalpha << test(baz, f) << std::endl; // 输出false
}

关键细节解释

  1. 区分函数指针与仿对象

    • 我们用is_function_pointer辅助模板来识别函数指针类型,这样可以针对两种Callable类型分别实现逻辑:
      • 函数指针场景:std::function内部直接存储函数指针,target<PtrType>会返回指向该指针的指针。我们需要先判断这个指针不为空(说明类型匹配),再比较内部指针和传入的f1是否相等。
      • 仿对象场景:std::function存储的是仿对象的副本,target<ObjType>返回指向这个副本的指针。我们需要先确认类型匹配,再通过operator==比较副本和传入对象的值是否相等(所以仿对象需要定义operator==,示例中用了默认生成的版本)。
  2. 为什么你之前的写法失败?

    • 你尝试的target<F1>或target<F2>没有考虑转发引用的类型推导问题:F1&&是转发引用,推导出来的类型可能包含引用或cv限定符,需要用std::decay_t去除这些修饰才能正确匹配target的模板参数。
    • target<F2>是错误的,因为F2是std::function的签名(比如int(int)),而不是Callable的实际类型,所以会返回nullptr。

边界情况说明

  • 如果你的std::function存储的是std::ref(bar)(引用包装),当前实现会返回false,因为target查询的是Callable类型,而内部存储的是std::reference_wrapper<Callable>。如果需要支持这种场景,可以添加额外的重载处理std::reference_wrapper。
  • 如果仿对象没有定义operator==,针对仿对象的重载会编译失败,这时候你要么添加operator==,要么修改逻辑为比较地址(但副本的地址肯定和原对象不同,意义不大)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:58:21