【问题标题】:c++11 : Compare lambda expressionc++11 : 比较 lambda 表达式
【发布时间】:2014-01-24 08:51:55
【问题描述】:

假设有以下课程:

#include <functional>
#include <vector>

template<typename T1> class Signaler
{
public:
  typedef std::function<void (T1)> Func;

public:
  Signaler()
  {
  }

  void Call(T1 arg)
  {
    for(Int32 i = (Int32)_handlers.size() - 1; i > -1; i--)
    {
      Func handler = _handlers[i];
      handler(arg);
    }
  }

  Signaler& operator+=(Func f)
  {
    _handlers.push_back( f );
    return *this;
  }

  Signaler& operator-=(Func f)
  {
    for(auto i = _handlers.begin(); i != _handlers.end(); i++)
    {
      if ( (*i).template target<void (T1)>() == f.template target<void (T1)>() )
      {
        _handlers.erase( i );
        break;
      }
    }

    return *this;
  }

private:
  std::vector<Func> _handlers;
};

我使用它的方式如下:

Signaler Global::Signal_SelectionChanged;

class C1
{
public:
    void Register()
    {
        Global::Signal_SelectionChanged   += [&](SelectionChangedEventArgs* e)  { this->selectionChangedEvent_cb(e); };
    }

    void Unregister()
    {
        Global::Signal_SelectionChanged   -= [&](SelectionChangedEventArgs* e)  { this->selectionChangedEvent_cb(e); };
    }

    void selectionChangedEvent_cb(SelectionChangedEventArgs* e) {}
};

class C2
{
public:
    void Register()
    {
        Global::Signal_SelectionChanged   += [&](SelectionChangedEventArgs* e)  { this->selectionChangedEvent_cb(e); };
    }

    void Unregister()
    {
        Global::Signal_SelectionChanged   -= [&](SelectionChangedEventArgs* e)  { this->selectionChangedEvent_cb(e); };
    }

    void selectionChangedEvent_cb(SelectionChangedEventArgs* e) {}
};

现在,我遇到的问题是,当我从 C2 类中调用“Unregister”时,它会删除错误版本的“lambda”表达式,因为“lambda”看起来很相似。

我该如何解决这个问题?

有什么想法吗?

谢谢

【问题讨论】:

  • 或许使用一些id来注销会更好?在我制作的信号管理器中,我将处理程序存储在一个列表中。 register 函数返回一个指向新处理程序的列表迭代器。 Unregister 将其作为参数并使用它来删除处理程序。另一种选择是使用整数 id 并将处理程序存储在 int => 处理程序映射中。
  • 两个std::function&lt;T&gt; 的目标可以以您使用的方式进行有意义的比较,因此除非您发布一些相关代码显示您填充向量然后尝试删除并随后获得结果 - 所以我们有一个希望发现你的实际错误 - 这个问题是在浪费时间......
  • 嗨,填充向量的代码在那里!!!调用注册/取消注册时,请参阅 C1 和 C2 类。

标签: c++ templates c++11 lambda


【解决方案1】:

问题是您使用std::function::target 的类型不是std::function 中存储的对象的类型,因此它返回一个空指针。也就是说,您需要知道std::function中存储的对象的实际类型才能调用target

即使您使用用于添加回调的 lambda 闭包类型调用 target,这也不起作用,原因有两个:首先,lambda 闭包类型是唯一的 (5.1.2p3),因此 +=-= lambdas 有不同的类型,即使它们在语法上是相同的;其次,lambda 表达式的闭包类型未定义为具有 operator== (5.1.2p3-6, 19-20),因此您的代码甚至无法编译。

从 lambda 切换到 std::bind 并没有帮助,因为绑定类型也未定义为具有 operator==

相反,请考虑使用 id 来注册/取消注册回调。您也可以使用自己的定义operator== 的函子,但这将是很多工作。

【讨论】:

    猜你喜欢
    • 2015-04-18
    • 1970-01-01
    • 2013-01-31
    • 2011-04-24
    • 2012-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多