雷人宝宝
雷人宝宝

Reputation: 11

How can boost signal disconnect signal?

As boost_offical_web_site says, boost::function is not comparable。but I am doubt about the usage:

#include <boost/signals2.hpp>

class B {
public:
    ~B() {
        printf("B dealloc:%p\n", this);
    }
    void OnSignalActive(void) {
        printf("B get signal address:%p\n", this);
    }
};

void test05() {
    boost::signals2::signal<void (void)> signalConnection;
    B b;
    
    auto v = boost::bind(&B::OnSignalActive, &b);
    auto u = boost::bind(&B::OnSignalActive, &b);
    
//    if (v == u) {//compile error
//
//    }
    
    boost::signals2::slot<void (void)> slot1(v);
    boost::signals2::slot<void (void)> slot2(v);
    
//    if (slot1.slot_function() == slot2) {//compile error
//
//    }
    
    boost::signals2::connection conn = signalConnection.connect(v);
    
    signalConnection();
    
    signalConnection.disconnect(u);
    
    signalConnection();
}

int main(int argc, const char * argv[]) {
    test05();
    return 0;
}

the code signalConnection.disconnect(u) can disconnect signal and runs well.I suspend boost do comparision by slot. so I debug into source:

void do_disconnect(const T &slot, mpl::bool_<false> /* is_group */)
{
  shared_ptr<invocation_state> local_state =
    get_readable_state();
  typename connection_list_type::iterator it;
  for(it = local_state->connection_bodies().begin();
    it != local_state->connection_bodies().end(); ++it)
  {
    garbage_collecting_lock<connection_body_base> lock(**it);
    if((*it)->nolock_nograb_connected() == false) continue;
    if((*it)->slot().slot_function() == slot)
    {
      (*it)->nolock_disconnect(lock);
    }else
    {
      // check for wrapped extended slot
      bound_extended_slot_function_type *fp;
      fp = (*it)->slot().slot_function().template target<bound_extended_slot_function_type>();
      if(fp && *fp == slot)
      {
        (*it)->nolock_disconnect(lock);
      }
    }
  }
}

found that inner uses == to disconnect.one is slot_function(actual boost::function) and another is slot. But when I manually create boost::signals2::slot. could not compare!

/main.cpp:303:31: note: in instantiation of function template specialization 'boost::operator==<boost::signals2::slot<void ()>>' requested here
if (slot1.slot_function() == slot2) {//compile error

I confused very much.

how can boost disconnect like this? using slot & slot_function? why manually create could not compare?

can someone help me!3Q in advance.

help me & answer the question.

Upvotes: 1

Views: 60

Answers (1)

sehe
sehe

Reputation: 392833

The actual line is

if((*it)->slot().slot_function().contains(slot))

Which indeed ends up comparing the functions type-erased targets, if the typeid matches. This behaviour may be overrided for your own types by creating your own overload of function_equal to be found by ADL. (See also Comparing Boost.Function Objects)

Boost bind expressions can be compared if the bound expressions can be. Replacing with std::bind makes it fail.

It's an implementation but indeed putting a stub like

friend bool function_equal_impl(auto&&...) { return false; }

Makes it compile with std::bind. Of course, it won't really compare now.

In short, don't use disconnect(handler) unless your handlers are comparable. If you have handlers that cannot be compared, use scoped_connection instead:

Live On Coliru

#include <boost/signals2.hpp>
namespace signals2 = boost::signals2;

#define TRACE(code) do { printf("%d: %s\n", __LINE__, #code); code; } while (0)

void test05() {
    signals2::signal<void()> signal;

    signals2::scoped_connection v = signal.connect([] { printf("Handler: V\n"); });
    signals2::scoped_connection u = signal.connect([] { printf("Handler: U\n"); });
    TRACE(signal());
    TRACE(v.disconnect());
    TRACE(signal());
}

Printing Live On Coliru

11: signal()
Handler: V
Handler: U
12: v.disconnect()
13: signal()
Handler: U

Upvotes: 0

Related Questions