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

C++17中为各类可调用对象生成唯一ID的实现方案

实现异构可调用容器的contains函数

针对需求——在存储Function指针的异构容器中判断是否包含指定可调用对象(支持函数指针、成员函数指针、可调用类,lambda始终返回false,舍弃std::function支持),以下是可行实现方案:


1. 扩展基类Function,添加匹配接口

给抽象基类新增纯虚函数matches,用于类型擦除后的匹配判断:

class Function
{
public:
    Function(std::string name)
     : m_name(name)
    {}

    virtual ~Function(){}

    std::string name() {
        return m_name;
    }
    
    template <typename... Args>
    decltype(auto) operator()(Args&&... args)
    {
         // 原有委托逻辑保留,此处简化
         return;
    }

    // 新增:判断当前可调用对象是否与目标匹配
    virtual bool matches(const std::any& target) const = 0;

private:
    std::string m_name;
    virtual std::any invoke(std::initializer_list<std::any> const& args) const = 0;
};

2. 在FunctionImpl中实现匹配逻辑

针对具体可调用类型F,重写matches函数,尝试将传入的std::any转换为F类型后做相等比较:

template <typename F>
class FunctionImpl : public Function
{
public:
    FunctionImpl(F const& f, std::string name)
     : Function(name)
     , function(f)
    {}

private:
    std::any invoke(std::initializer_list<std::any> const& args) const override
    {
        return std::any();
    }

    bool matches(const std::any& target) const override
    {
        // 尝试将目标转换为当前可调用类型
        if (const auto* target_ptr = std::any_cast<const F>(&target))
        {
            // 函数指针/成员函数指针直接比较地址;可调用类需支持==运算符
            return *target_ptr == function;
        }
        return false;
    }

    F function;
};

3. 实现contains函数

遍历容器,调用每个Function对象的matches方法,同时对lambda直接返回false:

首先定义lambda类型判断工具:

#include <type_traits>

template <typename T>
struct is_lambda : std::false_type {};

// 通用lambda判断:匹配带operator()的匿名类类型(排除函数指针、成员函数指针等)
template <typename T>
struct is_lambda<T> : std::integral_constant<bool,
    std::is_class_v<std::decay_t<T>> &&
    !std::is_function_v<std::decay_t<T>> &&
    !std::is_member_function_pointer_v<std::decay_t<T>> &&
    requires(T t) { t.operator()(); }> {};

template <typename T>
constexpr bool is_lambda_v = is_lambda<T>::value;

然后实现contains:

template <typename F>
bool contains(FContainer const& vec, F const& f)
{
    // 按照要求:lambda的contains始终返回false
    if constexpr (is_lambda_v<F>)
    {
        return false;
    }
    else
    {
        std::any target = f;
        for (const auto& func : vec)
        {
            if (func->matches(target))
            {
                return true;
            }
        }
        return false;
    }
}

4. 补充可调用类的相等运算符

自定义可调用类需要显式定义operator==才能支持匹配判断:

struct ACallableClass { 
    void operator()(){} 
    // C++20及以上可使用default生成默认相等逻辑
    bool operator==(const ACallableClass&) const = default;
};

完整测试代码

#include <any>
#include <string>
#include <memory>
#include <vector>
#include <cassert>
#include <type_traits>

// lambda类型判断工具
template <typename T>
struct is_lambda : std::false_type {};

template <typename T>
struct is_lambda<T> : std::integral_constant<bool,
    std::is_class_v<std::decay_t<T>> &&
    !std::is_function_v<std::decay_t<T>> &&
    !std::is_member_function_pointer_v<std::decay_t<T>> &&
    requires(T t) { t.operator()(); }> {};

template <typename T>
constexpr bool is_lambda_v = is_lambda<T>::value;

class Function
{
public:
    Function(std::string name)
     : m_name(name)
    {}

    virtual ~Function(){}

    std::string name() {
        return m_name;
    }
    
    template <typename... Args>
    decltype(auto) operator()(Args&&... args)
    {
         return;
    }

    virtual bool matches(const std::any& target) const = 0;

private:
    std::string m_name;
    virtual std::any invoke(std::initializer_list<std::any> const& args) const = 0;
};

template <typename F>
class FunctionImpl : public Function
{
public:
    FunctionImpl(F const& f, std::string name)
     : Function(name)
     , function(f)
    {}

private:
    std::any invoke(std::initializer_list<std::any> const& args) const override
    {
        return std::any();
    }

    bool matches(const std::any& target) const override
    {
        if (const auto* target_ptr = std::any_cast<const F>(&target))
        {
            return *target_ptr == function;
        }
        return false;
    }

    F function;
};

using FPointer = std::unique_ptr<Function>;

template <typename F>
FPointer make_function(F const& f, std::string name)
{
    return std::make_unique<FunctionImpl<F>>(f, name);
}

using FContainer = std::vector<FPointer>;

template <typename F>
bool contains(FContainer const& vec, F const& f)
{
    if constexpr (is_lambda_v<F>)
    {
        return false;
    }
    else
    {
        std::any target = f;
        for (const auto& func : vec)
        {
            if (func->matches(target))
            {
                return true;
            }
        }
        return false;
    }
}

void bar(){} void foo(){} 
struct AClass { void MemberFunction1(){} void MemberFunction2(){} };
struct ACallableClass { 
    void operator()(){} 
    bool operator==(const ACallableClass&) const = default;
};

int main()
{
    FContainer v;
    v.push_back(make_function(&foo, "foo"));
    v.push_back(make_function(&AClass::MemberFunction1, "AClass::MemberFunction1"));
    v.push_back(make_function(ACallableClass(), "CallableClass"));
    v.push_back(make_function([](){}, "empty lambda"));

    assert(contains(v, &foo));
    assert(contains(v, &AClass::MemberFunction1));
    assert(!contains(v, [](){}));

    assert(!contains(v, &bar));
    assert(!contains(v, &AClass::MemberFunction2));

    return 0;
}

关键说明

  • 类型擦除匹配:通过std::any实现类型安全的跨类型匹配,FunctionImpl仅处理自身存储的可调用类型,避免类型错误。
  • lambda处理:利用类型 trait 识别lambda类型,直接返回false,符合需求。
  • 相等比较:函数指针、成员函数指针直接比较内存地址;可调用类需显式定义operator==(C++20可使用=default生成默认实现)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 12:15:40