可以比较两个函子是否相等吗?

Can two functors be compared for equality?

有没有办法让接收两个仿函数作为参数的方法查明它们是否指向同一个函数?具体来说,具有这样的结构:

struct FSMAction {
    void action1() const { std::cout << "Action1 called." << std::endl; }
    void action2() const { std::cout << "Action2 called." << std::endl; }
    void action3() const { std::cout << "Action3 called." << std::endl; }

private:
    // Maybe some object-specific stuff.
};

还有这样的方法:

bool actionsEqual(
    const std::function<void(const FSMAction&)>& action1, 
    const std::function<void(const FSMAction&)>& action2)
{
    // Some code.
}

是否有 "some code" 将 return true 仅用于:

actionsEqual(&FSMAction::action1, &FSMAction::action1)

但不适用于:

actionsEqual(&FSMAction::action1, &FSMAction::action2)

也许这个问题没有任何意义(第一个线索是互联网上似乎没有关于它的任何信息......)。如果是这样,你能给个提示吗,为什么,如果有办法完成某事"similar"? (基本上,我想要一组只有 "unique" 项目的回调,在上面概述的意义上。)

原始函数最终是一个指针。您可以 dig it outstd::functionstd::function::target 然后它只是 void* 的比较。

按照 Michael Chourdakis 的回答直接使用 std::function::target<T>() 是有问题的,因为要使用它,您必须知道存储在 std::function:

中的实际类型

Return value

A pointer to the stored function if target_type() == typeid(T), otherwise a null pointer.

例如通过使用 T = void (A::*)() const,您可以限制自己仅使用 class FSMActionvoid() const 成员函数。在这一点上 std::function 开始并不比普通成员函数指针好。


我建议为 std::function 编写一个包装器,使用类型擦除实现 == / !=。这是一个最小的实现:

#include <functional>
#include <iostream>
#include <utility>

template <typename T>
class FancyFunction;

template <typename ReturnType, typename ...ParamTypes>
class FancyFunction<ReturnType(ParamTypes...)>
{
    using func_t = std::function<ReturnType(ParamTypes...)>;
    func_t func;
    bool (*eq)(const func_t &, const func_t &) = 0;

  public:
    FancyFunction(decltype(nullptr) = nullptr) {}

    template <typename T>
    FancyFunction(T &&obj)
    {
        func = std::forward<T>(obj);    
        eq = [](const func_t &a, const func_t &b)
        {
            return *a.template target<T>() ==
                   *b.template target<T>();
        };
    }

    explicit operator bool() const
    {
        return bool(func);
    }

    ReturnType operator()(ParamTypes ... params) const
    {
        return func(std::forward<ParamTypes>(params)...);
    }

    bool operator==(const FancyFunction &other) const
    {
        if (func.target_type() != other.func.target_type())
            return 0;
            
        if (!eq)
            return 1;
        
        return eq(func, other.func);
    }
    
    bool operator!=(const FancyFunction &other) const
    {
        return !operator==(other);
    }
};


struct A
{
    void foo() {}
    void bar() {}
};

int main()
{
    FancyFunction<void(A &)> f1(&A::foo), f2(&A::foo), f3(&A::bar);
    std::cout << (f1 == f2) << '\n';
    std::cout << (f1 == f3) << '\n';
}

Try it live