How to connect to a boost::signal with a generic function/slot?

966 Views Asked by At

Is it possible to connect a function with a different signature to a Boost::Signal which expects a certain signature?

I have many signals (of varying signature) And from outside that module I want to be able to observe the signals without caring about the signature of the signals. Is it even possible?

Example:

float sum(float x, float y)
{
  return x + y;
}

void signal_monitor(void)
{
  //Do something
}

boost::signal<float (float, float)> sig;

sig.connect(&print_sum);
sig.connect(/* How to connect to signal_monitor ?  */);

sig(5, 3);

Is it possible to use Boost::Bind to do it?

Boost version used:1.46.1

If I Use

sig.connect( ( boost::phoenix::bind( &signal_monitor ), 1.f ) ); // Return 1.f

I get the following errors:

opt/include/boost/function/function_template.hpp: In static member function ‘static R boost::detail::function::function_obj_invoker2<FunctionObj, R, T0, T1>::invoke(boost::detail::function::function_buffer&, T0, T1) [with FunctionObj = float, R = float, T0 = float, T1 = float]’:
opt/include/boost/function/function_template.hpp:913:60:   instantiated from ‘void boost::function2<R, T1, T2>::assign_to(Functor) [with Functor = float, R = float, T0 = float, T1 = float]’
opt/include/boost/function/function_template.hpp:722:7:   instantiated from ‘boost::function2<R, T1, T2>::function2(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = float, R = float, T0 = float, T1 = float, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
opt/include/boost/function/function_template.hpp:1064:16:   instantiated from ‘boost::function<R(T0, T1)>::function(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = float, R = float, T0 = float, T1 = float, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
opt/include/boost/function/function_template.hpp:1105:5:   instantiated from ‘typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, boost::function<R(T0, T1)>&>::type boost::function<R(T0, T1)>::operator=(Functor) [with Functor = float, R = float, T0 = float, T1 = float, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, boost::function<R(T0, T1)>&>::type = boost::function<float(float, float)>&]’
opt/include/boost/signals2/detail/slot_template.hpp:156:9:   instantiated from ‘void boost::signals2::slot2<R, T1, T2, SlotFunction>::init_slot_function(const F&) [with F = float, R = float, T1 = float, T2 = float, SlotFunction = boost::function<float(float, float)>]’
opt/include/boost/signals2/detail/slot_template.hpp:81:9:   instantiated from ‘boost::signals2::slot2<R, T1, T2, SlotFunction>::slot2(const F&) [with F = float, R = float, T1 = float, T2 = float, SlotFunction = boost::function<float(float, float)>]’
../../../example/example.cpp:200:61:   instantiated from here
opt/include/boost/function/function_template.hpp:132:42: error: ‘* f’ cannot be used as a function
opt/include/boost/function/function_template.hpp:133:9: error: control reaches end of non-void function [-Werror=return-type]
cc1plus: all warnings being treated as errors
make[1]: *** [example.o] Error 1

Many Thanks guys.

2

There are 2 best solutions below

5
On BEST ANSWER

Yes:

sig.connect( boost::bind( &signal_monitor ) );

Bind simply won't forward the arguments.

EDIT: As mentioned by Luc this won't work due to the bind expression returning nothing, perhaps there's a different solution using just boost bind, but another is to bring out the big guns, boost::phoenix ( #include "boost/phoenix.hpp" ):

sig.connect( ( boost::phoenix::bind( &signal_monitor ), 1.f ) ); // Return 1.f

Notice the extra (), otherwise you're still passing parameters to connect.

0
On

I would expect that it's forbidden to allow a function which returns void to be used in place of a function which is meant to return float; because if the return value is actually used for something then the value will be undefined, and so the behaviour of the program may turn out to be unpredictable.

So I'm pretty sure the only way to do what you are trying to do is to create a new function with the correct signature, and then have that function simply call your void function and return 0. In C++11, I think this will work:

sig.connect([](float, float)->float { signal_monitor(); return 0.0f; });