【问题标题】:Vector of std::function<>std::function<> 的向量
【发布时间】:2011-06-02 20:25:01
【问题描述】:

说要存储以下内容:

typedef std::function<void(int)> MyFunctionDecl;

..在一个集合中:

typedef std::vector<MyFunctionDecl> FunctionVector;
FunctionVector v;

这是可能的,但如果我想找到使用std::find的东西:

FunctionVector::const_iterator cit = std::find(v.begin(), v.end(), myFunctionDecl);

.. 由于== 运算符,我们得到一个错误。

正如在上一个问题中向我建议的那样,这可以通过将函数声明封装在另一个类中来解决,该类提供== 运算符:

class Wrapper
{
private:
    MyFunctionDecl m_Func;

public:
    // ctor omitted for brevity

    bool operator == (const Wrapper& _rhs)
    {
         // are they equal?
    }; // eo ==
};  // eo class Wrapper

所以我想做的是以某种方式为“MyFunctionDecl”生成一个哈希,以便我可以正确实现== 运算符。我可以有某种唯一标识符,并要求调用者为委托提供唯一标识符,但这似乎有点麻烦并且容易出错。

有没有办法可以做到这一点?这样相同的函数将返回相同的 ID 用于比较目的吗?到目前为止,解决它的唯一方法是放弃使用std::function 的概念,转而使用支持比较的快速委托。但后来我失去了使用 lambdas 的能力。

任何帮助表示赞赏!

编辑

鉴于下面的答案,这就是我想出的......我可能错过的任何警告?我现在正在逐步完成它:

class MORSE_API Event : boost::noncopyable
{
public:
    typedef std::function<void(const EventArgs&)> DelegateType;
    typedef boost::shared_ptr<DelegateType> DelegateDecl;

private:
    typedef std::set<DelegateDecl> DelegateSet;
    typedef DelegateSet::const_iterator DelegateSet_cit;
    DelegateSet m_Delegates;

public:
    Event()
    {
    };  // eo ctor


    Event(Event&& _rhs) : m_Delegates(std::move(_rhs.m_Delegates))
    {
    };  // eo mtor

    ~Event()
    {
    };  // eo dtor

    // methods
    void invoke(const EventArgs& _args)
    {
        std::for_each(m_Delegates.begin(),
                      m_Delegates.end(),
                      [&_args](const DelegateDecl& _decl) { (*_decl)(_args); });
    };  // eo invoke

    DelegateDecl addListener(DelegateType f)
    {
        DelegateDecl ret(new DelegateType(f));
        m_Delegates.insert(ret);
        return ret;
    };  // eo addListener

    void removeListener(const DelegateDecl _decl)
    {
        DelegateSet_cit cit(m_Delegates.find(_decl));
        if(cit != m_Delegates.end())
            m_Delegates.erase(cit);
    };  // eo removeListener

};  // eo class Event

【问题讨论】:

  • 为什么需要查找?如果您需要像这样找到 std::function,您需要根据一些标识符或类似的标识符来找到它,比如为您创建的每个新 Wrapper 自动生成一个 int。获取 int 以供将来比较,并确保每个包装器只创建一次。
  • 无法比较函数,这是停机问题 (en.wikipedia.org/wiki/Halting_problem)
  • @Alexandre 我认为停机问题是相关的,但绝对不一样。我认为散列的想法是你不需要运行函数来比较它。
  • @villintehaspam,添加和迭代不是问题。但是,想要创建一个允许存储多个委托的事件类型类,如果他们愿意,也可以删除自己。将addListenerremoveListener 视为此类事物的接口。
  • @Moo-Juice,在这种情况下,您将永远不会再为相同的函数生成新的包装器,因此使用我上面评论中的整数会很好。只需让 addListener 返回唯一标识符并让 removeListener 将其作为参数。

标签: c++ function hash c++11


【解决方案1】:

你看过Boost Signals吗?它可能已经在做你想做的事了。

无论如何,包装function 的一种简单方法是使用shared_ptr。如果你这样做了

typedef std::shared_ptr<std::function<void(int)> > MyFunctionDecl;

并确保在创建函数时立即将函数包装在 shared_ptr 中(以便指针是唯一的),可以测试指针是否相等,以便 std::find 可以工作。

例如,您可以使用像

这样的工厂函数来执行此操作
template <class Functor>
MyFunctionDecl createDelegate(Functor f) {
    return MyFunctionDecl(new std::function<void(int)>(f));
}

这样您在创建委托时为函数(其指针)提供唯一标识。

顺便说一句,我会使用std::set 而不是std::vector,因为finderase 都是对数而非线性。

【讨论】:

  • 感谢您。我已经根据您的想法创建了一个实现,现在正在检查它。已修改我的原始帖子以显示当前代码。谢谢!
【解决方案2】:
#include <boost/type_traits.hpp>
#include <iostream>

template<typename T>
class Wrapper
{
    private:
       T m_Func;

    public:

       template<typename U>
       bool operator==(const Wrapper<U>& _rhs)
       {
           return boost::is_same<T, U>::value;
       }
};

int main()
{
    Wrapper<int> Wint;
    Wrapper<bool> Wbool;
    std::cout << (Wint == Wbool) << std::endl;
    std::cout << (Wint == Wint) << std::endl;
}

【讨论】:

  • 这并不能真正解决问题。 boost::is_same 检查类型相等,而不是对象相等。
  • 但是 Wrapper 有一个 operator==
  • 是的,很多其他类也无济于事...... :)
  • 您对这个解决方案有什么问题?
  • 这不是解决方案,这就是问题所在。您无法区分两个不同的 Wrapper<:function>> .
猜你喜欢
  • 2023-02-07
  • 1970-01-01
  • 2014-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多