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

如何在vector中查找并移除lambda?遇operator==匹配错误求解

解决vector中std::variant包含std::function时的查找删除错误

问题描述

尝试在存储std::variant<std::function<void()>, Subscription*>的vector中查找并移除元素时,出现如下编译错误:

no match for 'operator==' (operand types are 'const std::function<void()>' and 'const std::function<void()>')

相关代码:

using TeardownLogic = variant<function<void()>, Subscription*>;

class Example {
  vector<TeardownLogic> finalizers = vector<TeardownLogic>();

  void add(TeardownLogic teardown) { this->finalizers.push_back(teardown); }

  void remove(TeardownLogic teardown) {
    auto idx = find(this->finalizers.begin(), this->finalizers.end(), teardown);
    if (idx != this->finalizers.end()) {
      this->finalizers.erase(idx);
    }
  }
};

原因分析

std::function默认不支持直接用==比较:

  • 若存储的是普通函数指针,可以比较;但如果是lambda(尤其是带捕获的lambda),其闭包类型无法生成合法的operator==,导致std::variant的默认相等比较失效。
  • std::find依赖元素的operator==,当variant持有std::function时,就会触发上述编译错误。

解决方案

方案一:用唯一标识包装可调用对象(最可靠)

给每个std::function分配唯一ID,通过ID来匹配元素,避免直接比较std::function:

#include <atomic>

struct TaggedFunc {
    static std::atomic_size_t next_id;
    size_t id;
    std::function<void()> func;

    TaggedFunc(std::function<void()> f) : id(next_id++), func(std::move(f)) {}
};

std::atomic_size_t TaggedFunc::next_id = 0;

using TeardownLogic = std::variant<TaggedFunc, Subscription*>;

class Example {
  std::vector<TeardownLogic> finalizers;

  void add(TeardownLogic teardown) { finalizers.push_back(std::move(teardown)); }

  void remove(const TeardownLogic& teardown) {
    auto idx = std::find_if(finalizers.begin(), finalizers.end(),
        [&teardown](const TeardownLogic& elem) {
            if (std::holds_alternative<TaggedFunc>(elem) && std::holds_alternative<TaggedFunc>(teardown)) {
                return std::get<TaggedFunc>(elem).id == std::get<TaggedFunc>(teardown).id;
            } else if (std::holds_alternative<Subscription*>(elem) && std::holds_alternative<Subscription*>(teardown)) {
                return std::get<Subscription*>(elem) == std::get<Subscription*>(teardown);
            }
            return false;
        });
    if (idx != finalizers.end()) {
        finalizers.erase(idx);
    }
  }
};

方案二:仅针对无捕获lambda/函数指针的场景适配

如果你的std::function只存储无捕获lambda或普通函数指针,可以通过target()方法获取底层指针进行比较:

void remove(const TeardownLogic& teardown) {
    auto idx = std::find_if(finalizers.begin(), finalizers.end(),
        [&teardown](const TeardownLogic& elem) {
            if (std::holds_alternative<std::function<void()>>(elem) && std::holds_alternative<std::function<void()>>(teardown)) {
                const auto& func_elem = *std::get<std::function<void()>>(elem);
                const auto& func_teardown = *std::get<std::function<void()>>(teardown);
                // 仅当存储的是函数指针或无捕获lambda时有效
                return func_elem.target<void(*)()>() == func_teardown.target<void(*)()>();
            } else if (std::holds_alternative<Subscription*>(elem) && std::holds_alternative<Subscription*>(teardown)) {
                return std::get<Subscription*>(elem) == std::get<Subscription*>(teardown);
            }
            return false;
        });
    if (idx != finalizers.end()) {
        finalizers.erase(idx);
    }
}

注意:带捕获的lambda无法用这种方法比较,会导致匹配失败。

方案三:替换std::function为可比较的类型

如果业务允许,可以放弃std::function,改用明确的函数指针+对象指针组合,比如:

using TeardownFunc = std::pair<Subscription*, void(Subscription::*)()>;
using TeardownLogic = std::variant<TeardownFunc, Subscription*>;

这种情况下可以直接通过指针比较来匹配元素。

内容的提问来源于stack exchange,提问作者Get Off My Lawn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 21:20:19