boost signals2 - error when pass a slot to disconnect - c++

I want to pass a slot to disconnect like in the boost signals2 documentation:
Pass slot to disconnect: in this interface model, the disconnection of
a slot connected with sig.connect(typeof(sig)::slot_type(slot_func))
is performed via sig.disconnect(slot_func).
#include <iostream>
#include <boost/signals2.hpp>
class Test {
public:
Test();
using Signal = boost::signals2::signal<void ()>;
void slot();
void test();
};
Test::Test() {
boost::function<void ()> boundSlot = boost::bind(&Test::slot, this);
Signal sig;
sig.connect(Signal::slot_type(boundSlot));
sig();
sig.disconnect(boundSlot);
};
void Test::slot() {
std::cout << "slot()" << std::endl;
};
int main()
{
Test aTest;
return 0;
}
... but I got an error when calling disconnect (see http://cpp.sh/45q6):
error: ambiguous overload for 'operator=='
(operand types are 'boost::signals2::slot >::slot_function_type
{aka boost::function}'
and 'const boost::function')
What do I wrong?

Problem is, that std::function has no operator == for function compare, only for function and nullptr, but it's required, so you just can use boost::function, which has compare operator and boost::bind.

Related

Creating wrapper over boost::deadline_timer, not able to pass parameter to handler function

I am trying to create a simple BoostTimer class which wraps deadline_timer's essential functions such as async_wait and cancel, so that my program just calls startTimer and killTimer, I have written following code
boosttimer.h
#ifndef __BOOST_TIMER__
#define __BOOST_TIMER__
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/chrono.hpp>
#include <boost/chrono/duration.hpp>
#include <boost/function.hpp>
class BoostTimer{
public:
typedef boost::asio::deadline_timer deadline_timer;
typedef deadline_timer::duration_type duration;
typedef boost::function<void (boost::system::error_code, BoostTimer&)> handler_function;
BoostTimer(boost::asio::io_service& io_service, duration interval, handler_function handler);
~BoostTimer();
void startTimer();
void killTimer();
private:
deadline_timer _timer;
boost::asio::io_service& _ioService;
duration _interval;
handler_function _handler;
};
#endif
boosttimer.cpp
#include "boosttimer.h"
BoostTimer::BoostTimer(boost::asio::io_service& io_service, duration interval, handler_function handler) :
_timer(io_service),
_ioService(io_service),
_interval(interval),
_handler(handler)
{
}
BoostTimer::~BoostTimer()
{
}
void BoostTimer::startTimer()
{
_timer.expires_from_now(_interval);
_timer.async_wait(boost::bind(_handler, boost::asio::placeholders::error, boost::ref(*this))); //trying to pass placeholder argument but somehow it doesn't work
}
void BoostTimer::killTimer()
{
_timer.cancel();
}
timertest.cpp
#include <iostream>
#include <boost/asio.hpp>
#include "boosttimer.h"
//void timer_handler(const boost::system::error_code& /*e*/) // not able to take parameters
void timer_handler() //it runs fine without parameters
{
std::cout<<"timer function has been called" << std::endl;
}
int main(int argc, char* argv[])
{
boost::asio::io_service io_service;
BoostTimer timer(io_service,boost::posix_time::seconds(5), boost::bind(&timer_handler));
timer.startTimer();
io_service.run();
return 0;
}
My question is how can i pass parameters to my handler function from my BoostTimer class's startTimer function ? I tried it but I am missing something.
If you just want to pass arguments from the caller:
void timer_handler(std::string const& arg1, int arg2)
{
std::cout<<"timer function has been called with arg1='" << arg1 <<"', arg2=" << arg2 << std::endl;
}
int main()
{
boost::asio::io_service io_service;
BoostTimer timer(io_service,boost::posix_time::seconds(5), boost::bind(&timer_handler, "This is arg1", 42));
timer.startTimer();
io_service.run();
return 0;
}
See it Live On Coliru, output:
timer function has been called with arg1='This is arg1', arg2=42
To also pass ec and *this:
CAVEAT I think this seriously breaks any encapsulation and makes the whole class basically redundant. Consider not calling the completion handler in case of cancellation e.g. Also, let the caller bind the objects instances it requires (it's weird for the user-defined handler to require a reference to BoostTimer - that's tight coupling in the wrong direction)
void timer_handler(boost::system::error_code ec, BoostTimer& instance, std::string const& arg1, int arg2) //it runs fine without parameters
{
std::cout<<"timer function has been called with arg1='" << arg1 <<"', arg2=" << arg2 << " (" << ec.message() << ")\n";
}
int main()
{
boost::asio::io_service io_service;
BoostTimer timer(io_service,boost::posix_time::seconds(1), boost::bind(&timer_handler, _1, _2, "This is arg1", 42));
timer.startTimer();
io_service.run();
return 0;
}
See it Live On Coliru too, output:
timer function has been called with arg1='This is arg1', arg2=42 (Success)

C++ Threading with Boost Library

I want my function running in a separate thread. I use Boost library and include like this in my main.cpp:
#include <boost/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
I want the thread start like this:
boost::thread ethread(Engine::function,info);
// info is an object from the class Engine and i need this in the
// function
My Engine class is in the func.h and the function looks like this:
void Engine::function(Engine info)
{
//STUFF
boost::this_thread::sleep(boost::posix_time::milliseconds(1));
}
BTW: Is the sleep function for the thread right?
Every time I want to compile it gives me this error:
error C3867: "Engine::function": function call missing argument list; use '&Engine::function' to create a pointer to member
I tried to use &Engine::function in the thread and this error appears:
error C2064: term does not evaluate to a function taking 2 arguments
I also tried:
boost::thread ethread(Engine::function,info, _1);
Then this error appeared:
error C2784: "result_traits<R,F>::type boost::_bi::list0::operator [](const boost::_bi::bind_t<R,F,L> &) const"
Can someone help me with this? I only want to run the function beside the main thread.
You should use bind function to create functional object with pointer to class member function or make your function static.
http://ru.cppreference.com/w/cpp/utility/functional/bind
More detailed explanation:
boost::thread constructor needs pointer to a function. In case of normal functions syntax is simple: &hello
#include <boost/thread/thread.hpp>
#include <iostream>
void hello()
{
std::cout << "Hello world, I'm a thread!" << std::endl;
}
int main(int argc, char* argv[])
{
boost::thread thrd(&hello);
thrd.join();
return 0;
}
But if you need pointer to a function of class you have to remember that such functions have implicit parameter - this pointer, so you have to pass it also. You can do this by creating callable object with std::bind, or boost bind.
#include <iostream>
#include <boost/thread.hpp>
class Foo{
public:
void print( int a )
{
std::cout << a << std::endl;
}
};
int main(int argc, char *argv[])
{
Foo foo;
boost::thread t( std::bind( &Foo::print, &foo, 5 ) );
t.join();
return 0;
}

Bind SIGTERM to a member function

I would like to create a simple class to signals handling (just for study) with std::bind. However, I could not compile this code:
#include <iostream>
#include <functional>
#include <csignal>
using namespace std;
class SignalHandler
{
public:
void handler(int value)
{
cout << value << endl;
}
SignalHandler()
{
auto callback = std::bind(&SignalHandler::handler, this, std::placeholders::_1);
sighandler_t ret = std::signal(SIGTERM, callback);
if (SIG_ERR == ret) {
throw;
}
}
};
int main() {
SignalHandler handler;
raise(SIGTERM);
return 0;
}
(GCC) Compiler exit:
prog.cpp: In constructor 'SignalHandler::SignalHandler()':
prog.cpp:21:51: error: cannot convert 'std::_Bind(SignalHandler*, std::_Placeholder<1>)>' to '__sighandler_t {aka void ()(int)}' for argument '2' to 'void ( signal(int, __sighandler_t))(int)'
sighandler_t ret = std::signal(SIGTERM, callback);
You can use static methods to handle SIGTERM, et al. I've done that before. static was the key to get signatures to match.

std::function as sighandler_t

How to specify lambda, std::bind result or any other std::function as argument for unix signal function?
I'm trying the following
std::function<void(int)> handler1 = std::bind(&cancellation_token::cancel, &c);
std::function<void(int)> handler2 = [&c](int) { c.cancel(); };
but it doesn't work, because both
handler1.target<void(int)>()
and
handler2.target<void(int)>()
return null
It works if I initialize handler with free function pointer
void foo(int) { ... }
std::function<void(int)> handler = foo;
but this is absolutely useless. I need to capture some local variables, so I need either bind or lambda.
Actually I understand why it doesn't work. Documentation says that target function returns a pointer to the stored function if target_type() == typeid(T), otherwise a null pointer. I don't understand how to make it work.
Any suggestions?
Since it's constructed by bind, or lambda with captured-data, you cannot convert it to free function, since target function works by typeid, std::function saves it in runtime, not for type T, with which function is templated. For std::bind it will be some library-type and for lambda it will be some unnamed type.
You can use a dispatcher-like approach associating signal numbers to std::functions through a map.
You just need a map to hold the std::functions accesible from a free function:
std::unordered_map<int, std::function<void(int)>> signalHandlers;
And a generic handler (free function) to map the signal number to the function:
void dispatcher(int signal) {
// this will call a previously saved function
signalHandlers.at(signal)(signal);
}
Implementation example
main.cpp
#include <iostream>
#include <thread>
#include <csignal>
#include "cppsignal.hpp"
int main() {
bool stop = false;
// set a handler as easy as this
CppSignal::setHandler(SIGINT, [&stop] (int) { stop = true; });
while (!stop) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout << "Bye" << std::endl;
return 0;
}
cppsignal.cpp
#include <cstring> // strsignal
#include <csignal>
#include <string>
#include <stdexcept>
#include <unordered_map>
#include <mutex>
#include "signal.hpp"
namespace CppSignal {
std::timed_mutex signalHandlersMutex;
std::unordered_map<int, std::function<void(int)>> signalHandlers;
// generic handler (free function) to set as a handler for any signal
void dispatcher(int signal) {
std::unique_lock<std::timed_mutex> lock(signalHandlersMutex, std::defer_lock);
if (!lock.try_lock_for(std::chrono::seconds(1))) {
// unable to get the lock. should be a strange case
return;
}
auto it = signalHandlers.find(signal);
if (it != signalHandlers.end()) {
it->second(signal);
}
}
void registerHandler(int signal, const std::function<void(int)>& handler) {
std::lock_guard<std::timed_mutex> lock(signalHandlersMutex);
signalHandlers.emplace(signal, handler);
}
// this is the only method you will use
void setHandler(int signal, const std::function<void(int)>& handler, int flags) {
// configure sigaction structure
struct sigaction action;
if (sigfillset(&action.sa_mask) == -1) {
throw std::runtime_error("sigfillset failed");
}
action.sa_flags = flags;
action.sa_handler = dispatcher;
// set handler for the signal
if (sigaction(signal, &action, nullptr) == -1 && signal < __SIGRTMIN) {
throw std::runtime_error("Fail at configuring handler for signal: " + std::string(strsignal(signal)));
}
registerHandler(signal, handler);
}
}
cppsignal.hpp
#ifndef __CPPSIGNAL_HPP
#define __CPPSIGNAL_HPP
#include <functional>
namespace CppSignal {
void setHandler(int signal, const std::function<void(int)>& handler, int flags=0);
}
#endif
sighandler_t is defined to be a pointer to a function with the following definition:
void func(int);
Since std::bind and lambdas return functors, it is not possible to directly use them as signal handler. As a workaround you can use your own wrapper functions like
class SignalHandlerBase
{
public:
virtual void operator(int) = 0;
};
template <class T>
class SignalHandler : public SignalHandlerBase
{
T t;
public:
SignalHandler(T _t) : t(_t) { }
void operator(int i)
{
t(i);
}
};
class SignalManager
{
int sig;
SignalHandlerBase *shb;
static void handlerFunction(int i)
{
shb(i);
}
public:
SignalManager(int signal) : sig(signal), shb(nullptr) { signal(signal, &handlerFunction); }
template <class T>
void installHandler(T t)
{
delete shb;
shb = new SignalHandler<T>(t);
}
};
Use global instances of SignalManager to manage individual signals
C++11 1.9 [intro.execution]/6:
When the processing of the abstract machine is interrupted by receipt of a signal, the values of objects which
are neither
of type volatile std::sig_atomic_t nor
lock-free atomic objects (29.4)
are unspecified during the execution of the signal handler, and the value of any
object not in either of these
two categories that is modified by the handler becomes undefined.
The only action you can realistically take portably in a signal handler is to change the value of a flag whose type is volatile std::sig_atomic_t or a lock-free std::atomic (Note that not all std::atomic objects are lock-free). Non-signal handling code can then poll that flag to respond to the occurrence of the signal.
N3787 has some interesting discussion about how to fix C++11 basically breaking signal handlers as a concept.

Complete example using Boost::Signals for C++ Eventing

I’m aware of the tutorial at boost.org addressing this:
Boost.org Signals Tutorial, but the examples are not complete and somewhat over simplified. The examples there don’t show the include files and some sections of the code are a little vague.
Here is what I need:
ClassA raises multiple events/signals
ClassB subscribes to those events (Multiple classes may subscribe)
In my project I have a lower-level message handler class that raises events to a business class that does some processing of those messages and notifies the UI (wxFrames). I need to know how these all might get wired up (what order, who calls who, etc).
The code below is a minimal working example of what you requested. ClassA emits two signals; SigA sends (and accepts) no parameters, SigB sends an int. ClassB has two functions which will output to cout when each function is called. In the example there is one instance of ClassA (a) and two of ClassB (b and b2). main is used to connect and fire the signals. It's worth noting that ClassA and ClassB know nothing of each other (ie they're not compile-time bound).
#include <boost/signal.hpp>
#include <boost/bind.hpp>
#include <iostream>
using namespace boost;
using namespace std;
struct ClassA
{
signal<void ()> SigA;
signal<void (int)> SigB;
};
struct ClassB
{
void PrintFoo() { cout << "Foo" << endl; }
void PrintInt(int i) { cout << "Bar: " << i << endl; }
};
int main()
{
ClassA a;
ClassB b, b2;
a.SigA.connect(bind(&ClassB::PrintFoo, &b));
a.SigB.connect(bind(&ClassB::PrintInt, &b, _1));
a.SigB.connect(bind(&ClassB::PrintInt, &b2, _1));
a.SigA();
a.SigB(4);
}
The output:
Foo
Bar: 4
Bar: 4
For brevity I've taken some shortcuts that you wouldn't normally use in production code (in particular access control is lax and you'd normally 'hide' your signal registration behind a function like in KeithB's example).
It seems that most of the difficulty in boost::signal is in getting used to using boost::bind. It is a bit mind-bending at first! For a trickier example you could also use bind to hook up ClassA::SigA with ClassB::PrintInt even though SigA does not emit an int:
a.SigA.connect(bind(&ClassB::PrintInt, &b, 10));
Hope that helps!
Here is an example from our codebase. Its been simplified, so I don't guarentee that it will compile, but it should be close. Sublocation is your class A, and Slot1 is your class B. We have a number of slots like this, each one which subscribes to a different subset of signals. The advantages to using this scheme are that Sublocation doesn't know anything about any of the slots, and the slots don't need to be part of any inheritance hierarchy, and only need implement functionality for the slots that they care about. We use this to add custom functionality into our system with a very simple interface.
Sublocation.h
class Sublocation
{
public:
typedef boost::signal<void (Time, Time)> ContactSignal;
typedef boost::signal<void ()> EndOfSimSignal;
void endOfSim();
void addPerson(Time t, Interactor::Ptr i);
Connection addSignalContact(const ContactSignal::slot_type& slot) const;
Connection addSignalEndOfSim(const EndOfSimSignal::slot_type& slot) const;
private:
mutable ContactSignal fSigContact;
mutable EndOfSimSignal fSigEndOfSim;
};
Sublocation.C
void Sublocation::endOfSim()
{
fSigEndOfSim();
}
Sublocation::Connection Sublocation::addSignalContact(const ContactSignal::slot_type& slot) const
{
return fSigContact.connect(slot);
}
Sublocation::Connection Sublocation::addSignalEndOfSim(const EndOfSimSignal::slot_type& slot) const
{
return fSigEndOfSim.connect(slot);
}
Sublocation::Sublocation()
{
Slot1* slot1 = new Slot1(*this);
Slot2* slot2 = new Slot2(*this);
}
void Sublocation::addPerson(Time t, Interactor::Ptr i)
{
// compute t1
fSigOnContact(t, t1);
// ...
}
Slot1.h
class Slot1
{
public:
Slot1(const Sublocation& subloc);
void onContact(Time t1, Time t2);
void onEndOfSim();
private:
const Sublocation& fSubloc;
};
Slot1.C
Slot1::Slot1(const Sublocation& subloc)
: fSubloc(subloc)
{
subloc.addSignalContact(boost::bind(&Slot1::onContact, this, _1, _2));
subloc.addSignalEndSim(boost::bind(&Slot1::onEndSim, this));
}
void Slot1::onEndOfSim()
{
// ...
}
void Slot1::onContact(Time lastUpdate, Time t)
{
// ...
}
Did you look at boost/libs/signals/example ?
When compiling MattyT's example with newer boost (f.e. 1.61) then it gives a warning
error: #warning "Boost.Signals is no longer being maintained and is now deprecated. Please switch to Boost.Signals2. To disable this warning message, define BOOST_SIGNALS_NO_DEPRECATION_WARNING."
So either you define BOOST_SIGNALS_NO_DEPRECATION_WARNING to suppress the warning or you could easily switch to boost.signal2 by changing the example accordingly:
#include <boost/signals2.hpp>
#include <boost/bind.hpp>
#include <iostream>
using namespace boost::signals2;
using namespace std;
Boost like QT provides its own implementation of signals and slots. Following are some example of its implementation.
Signal and Slot connection for namespace
Consider a namespace called GStreamer
namespace GStremer
{
void init()
{
....
}
}
Here is how to create and trigger the signal
#include<boost/signal.hpp>
...
boost::signal<void ()> sigInit;
sigInit.connect(GStreamer::init);
sigInit(); //trigger the signal
Signal and Slot connection for a Class
Consider a Class called GSTAdaptor with function called func1 and func2 with following signature
void GSTAdaptor::func1()
{
...
}
void GSTAdaptor::func2(int x)
{
...
}
Here is how to create and trigger the signal
#include<boost/signal.hpp>
#include<boost/bind.hpp>
...
GSTAdaptor g;
boost::signal<void ()> sigFunc1;
boost::signal<void (int)> sigFunc2;
sigFunc1.connect(boost::bind(&GSTAdaptor::func1, &g);
sigFunc2.connect(boost::bind(&GSTAdaptor::func2, &g, _1));
sigFunc1();//trigger the signal
sigFunc2(6);//trigger the signal
Above answer is great with signal2 same answer shoule be rewritten:
#include <boost/signals2.hpp>
#include <boost/bind.hpp>
#include <iostream>
using namespace boost;
using namespace std;
struct ClassA
{
signals2::signal<void ()> SigA;
signals2::signal<void (int)> SigB;
};
struct ClassB
{
void PrintFoo() { cout << "Foo" << endl; }
void PrintInt(int i) { cout << "Bar: " << i << endl; }
};
int main()
{
ClassA a;
ClassB b, b2;
a.SigA.connect(bind(&ClassB::PrintFoo, &b));
a.SigB.connect(bind(&ClassB::PrintInt, &b, _1));
a.SigB.connect(bind(&ClassB::PrintInt, &b2, _1));
a.SigA();
a.SigB(4);
}