【问题标题】:Disconnecting a boost signals2 connection by functor通过函子断开升压信号2连接
【发布时间】:2012-06-19 07:36:42
【问题描述】:

我正在尝试将一些使用不同系统的代码转换为使用 Boost.Signals2。旧代码使用常规函数指针作为函子;连接是通过使用函子调用特定方法来完成的,而断开连接是通过使用完全相同的函子调用另一个方法来完成的。出于兼容性原因,我仍然想支持这个,即使我知道这不是 Signals2 下最有效的方法。

namespace bs2 = boost::signals2;
class Foo
{
    typedef bs2::signal<void (const Foo *foo)> UpdateEvent;
    UpdateEvent m_UpdateEvent;

public:
    typedef UpdateEvent::slot_type UpdateCallback;

    bs2::connection Register(const UpdateCallback& callback)
    {
        return m_UpdateEvent.connect(callback);
    }

    void Unregister(const UpdateCallback& callback)
    {
        m_UpdateEvent.disconnect(callback);
    }
};

上面的(简化的)代码可以正常连接,但是 Unregister 方法在 VS2008 中无法编译:

T:\boost\boost_1_47_0\boost/function_equal.hpp(17) : error C2678: binary '==' : no operator found which takes a left-hand operand of type 'const Foo::UpdateCallback' (or there is no acceptable conversion)
    T:\boost\boost_1_47_0\boost/function/function_base.hpp(808): could be 'bool boost::operator ==<T>(const boost::function_base &,Functor)'
    with
    [
        T=Foo::UpdateCallback,
        Functor=Foo::UpdateCallback
    ]
    T:\boost\boost_1_47_0\boost/function/function_base.hpp(817): or       'bool boost::operator ==<F>(Functor,const boost::function_base &)'
    with
    [
        F=Foo::UpdateCallback,
        Functor=Foo::UpdateCallback
    ]
    C:\Program Files\Microsoft SDKs\Windows\v6.0A\include\guiddef.h(192): or       'int operator ==(const GUID &,const GUID &)' [found using argument-dependent lookup]
    T:\boost\boost_1_47_0\boost/function/function_base.hpp(746): or       'bool boost::operator ==(const boost::function_base &,boost::detail::function::useless_clear_type *)'
    T:\boost\boost_1_47_0\boost/function/function_base.hpp(758): or       'bool boost::operator ==(boost::detail::function::useless_clear_type *,const boost::function_base &)'
    T:\boost\boost_1_47_0\boost/blank.hpp(58): or       'bool boost::operator ==(const boost::blank &,const boost::blank &)'
    while trying to match the argument list '(const Foo::UpdateCallback, const Foo::UpdateCallback)'
    T:\boost\boost_1_47_0\boost/function_equal.hpp(24) : see reference to function template instantiation 'bool boost::function_equal_impl<F,G>(const F &,const G &,long)' being compiled
    with
    [
        F=Foo::UpdateCallback,
        G=Foo::UpdateCallback
    ]
    T:\boost\boost_1_47_0\boost/function/function_base.hpp(811) : see reference to function template instantiation 'bool boost::function_equal<Functor,Functor>(const F &,const G &)' being compiled
    with
    [
        Functor=Foo::UpdateCallback,
        F=Foo::UpdateCallback,
        G=Foo::UpdateCallback
    ]
    T:\boost\boost_1_47_0\boost/signals2/detail/signal_template.hpp(527) : see reference to function template instantiation 'bool boost::operator ==<T>(const boost::function_base &,Functor)' being compiled
    with
    [
        T=Foo::UpdateCallback,
        Functor=Foo::UpdateCallback
    ]
    T:\boost\boost_1_47_0\boost/signals2/detail/signal_template.hpp(221) : see reference to function template instantiation 'void boost::signals2::detail::signal1_impl<R,T1,Combiner,Group,GroupCompare,SlotFunction,ExtendedSlotFunction,Mutex>::do_disconnect<T>(const T &,boost::mpl::bool_<C_>)' being compiled
    with
    [
        R=void,
        T1=const Foo *,
        Combiner=boost::signals2::optional_last_value<void>,
        Group=int,
        GroupCompare=std::less<int>,
        SlotFunction=boost::function<void (const Foo *)>,
        ExtendedSlotFunction=boost::function<void (const boost::signals2::connection &,const Foo *)>,
        Mutex=boost::signals2::mutex,
        T=Foo::UpdateCallback,
        C_=false
    ]
    T:\boost\boost_1_47_0\boost/signals2/detail/signal_template.hpp(691) : see reference to function template instantiation 'void boost::signals2::detail::signal1_impl<R,T1,Combiner,Group,GroupCompare,SlotFunction,ExtendedSlotFunction,Mutex>::disconnect<T>(const T &)' being compiled
    with
    [
        R=void,
        T1=const Foo *,
        Combiner=boost::signals2::optional_last_value<void>,
        Group=int,
        GroupCompare=std::less<int>,
        SlotFunction=boost::function<void (const Foo *)>,
        ExtendedSlotFunction=boost::function<void (const boost::signals2::connection &,const Foo *)>,
        Mutex=boost::signals2::mutex,
        T=Foo::UpdateCallback
    ]
    .\Foo.cpp(72) : see reference to function template instantiation 'void boost::signals2::signal1<R,T1,Combiner,Group,GroupCompare,SlotFunction,ExtendedSlotFunction,Mutex>::disconnect<Foo::UpdateCallback>(const T &)' being compiled
    with
    [
        R=void,
        T1=const Foo *,
        Combiner=boost::signals2::optional_last_value<void>,
        Group=int,
        GroupCompare=std::less<int>,
        SlotFunction=boost::function<void (const Foo *)>,
        ExtendedSlotFunction=boost::function<void (const boost::signals2::connection &,const Foo *)>,
        Mutex=boost::signals2::mutex,
        T=Foo::UpdateCallback
    ]

那么,不知何故,函数对象不能与自身进行比较?我还尝试将 slot_function_type 用于 UpdateCallback,并明确将其指定为具有相同签名的 boost::function;这两个都产生了这个错误:

T:\boost\boost_1_47_0\boost/signals2/detail/signal_template.hpp(527) : error C2666: 'boost::signals2::detail::operator ==' : 4 overloads have similar conversions
    T:\boost\boost_1_47_0\boost/function/function_template.hpp(997): could be 'void boost::operator ==<R,T0>(const boost::function1<R,T0> &,const boost::function1<R,T0> &)' [found using argument-dependent lookup]
    with
    [
        R=void,
        T0=const Foo *
    ]
    T:\boost\boost_1_47_0\boost/function/function_base.hpp(817): or       'bool boost::operator ==<boost::function<Signature>>(Functor,const boost::function_base &)' [found using argument-dependent lookup]
    with
    [
        Signature=void (const Foo *),
        Functor=boost::function<void (const Foo *)>
    ]
    T:\boost\boost_1_47_0\boost/function/function_base.hpp(808): or       'bool boost::operator ==<T>(const boost::function_base &,Functor)' [found using argument-dependent lookup]
    with
    [
        T=Foo::UpdateCallback,
        Functor=Foo::UpdateCallback
    ]
    or       'built-in C++ operator==(void (__thiscall boost::function1<R,T0>::dummy::* )(void), void (__thiscall boost::function1<R,T0>::dummy::* )(void))'
    with
    [
        R=void,
        T0=const Foo *
    ]
    while trying to match the argument list '(boost::function<Signature>, const Foo::UpdateCallback)'
    with
    [
        Signature=void (const Foo *)
    ]
    T:\boost\boost_1_47_0\boost/signals2/detail/signal_template.hpp(221) : see reference to function template instantiation 'void boost::signals2::detail::signal1_impl<R,T1,Combiner,Group,GroupCompare,SlotFunction,ExtendedSlotFunction,Mutex>::do_disconnect<T>(const T &,boost::mpl::bool_<C_>)' being compiled
    with
    [
        R=void,
        T1=const Foo *,
        Combiner=boost::signals2::optional_last_value<void>,
        Group=int,
        GroupCompare=std::less<int>,
        SlotFunction=boost::function<void (const Foo *)>,
        ExtendedSlotFunction=boost::function<void (const boost::signals2::connection &,const Foo *)>,
        Mutex=boost::signals2::mutex,
        T=Foo::UpdateCallback,
        C_=false
    ]
    T:\boost\boost_1_47_0\boost/signals2/detail/signal_template.hpp(691) : see reference to function template instantiation 'void boost::signals2::detail::signal1_impl<R,T1,Combiner,Group,GroupCompare,SlotFunction,ExtendedSlotFunction,Mutex>::disconnect<T>(const T &)' being compiled
    with
    [
        R=void,
        T1=const Foo *,
        Combiner=boost::signals2::optional_last_value<void>,
        Group=int,
        GroupCompare=std::less<int>,
        SlotFunction=boost::function<void (const Foo *)>,
        ExtendedSlotFunction=boost::function<void (const boost::signals2::connection &,const Foo *)>,
        Mutex=boost::signals2::mutex,
        T=Foo::UpdateCallback
    ]
    .\Foo.cpp(72) : see reference to function template instantiation 'void boost::signals2::signal1<R,T1,Combiner,Group,GroupCompare,SlotFunction,ExtendedSlotFunction,Mutex>::disconnect<Foo::UpdateCallback>(const T &)' being compiled
    with
    [
        R=void,
        T1=const Foo *,
        Combiner=boost::signals2::optional_last_value<void>,
        Group=int,
        GroupCompare=std::less<int>,
        SlotFunction=boost::function<void (const Foo *)>,
        ExtendedSlotFunction=boost::function<void (const boost::signals2::connection &,const Foo *)>,
        Mutex=boost::signals2::mutex,
        T=Foo::UpdateCallback
    ]

所以我想它已经从选择太少变成了太多。我该如何解决这个问题?

【问题讨论】:

  • 嗯,我想这可以解释为什么它不能直接工作,但不能解释如何让它工作。
  • 两年后,我也有同样的问题。如果我找到答案,我会发布答案。
  • FWIW,我最终放弃了这个想法并修改了调用代码以将 connection 保存为 scoped_connection
  • 这个问题在前面已经讨论过了。解决这个问题最简单的方法是使用 typedef + 常规函数指针。 typedef void (*Slot) (const Foo *foo);

标签: c++ visual-c++ boost boost-function boost-signals2


【解决方案1】:

boost::function 没有实现 operator==,所以我们不能像 f1 == f2 那样进行比较。 当我们需要从信号断开函数时,这会导致 boost::signal 库中的问题 通过使用 boost::function 作为参数。 boost::signal 试图通过将参数与自己的函数进行比较来查找函数,这会导致错误。我的解决方案如下。还提出了其他可能的解决方案,例如存储连接....如果我的方法适合您,您应该选择它,因为它不存储任何内容,因此您不需要处理手动连接管理。

class Button {
public:

    typedef void (*EventHandler)();
    typedef boost::signal<void ()> Event;

    Button () {
    }

    virtual ~Button () {
    }

    void addClickHandler(EventHandler handler) {
        clickEvent.connect(handler);
    }

    void removeClickHandler(EventHandler handler) {
        clickEvent.disconnect(handler);
    }

    void click() {
        clickEvent();
    }

private:
    Event clickEvent;
};

void print() {
    cout << "print" << endl;
}

void app1_TestButton() {
    Button b;
    b.addClickHandler(print);
    b.click();

    b.removeClickHandler(print);
    b.click();
}

【讨论】:

  • 这不是一个真正的解决方案,因为它只适用于一个裸函数指针,根据定义,它不能包含任何上下文,因此在你不能依赖全局单例的实际应用程序中基本上是无用的.
猜你喜欢
  • 1970-01-01
  • 2012-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-14
  • 1970-01-01
  • 2012-08-02
  • 2023-03-09
相关资源
最近更新 更多