1

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.

Sak
  • 269
  • 1
  • 4
  • 13

2 Answers2

1

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.

Ylisar
  • 4,293
  • 21
  • 27
  • There is the matter of the return type and value. – Luc Danton Aug 03 '12 at 14:50
  • Thanks for the quick response, I'm getting compilation errors If I call sig.connect( ( boost::phoenix::bind( &signal_monitor ), 1.f ) ); // Return 1.f and all the errors are criptic (as usual ;) ) "boost/function/function_template.hpp:132:42: error: ‘* f’ cannot be used as a function" – Sak Aug 03 '12 at 16:41
  • @user1574205 The provided example can be made to work, so you need to be provide more information. E.g. a link to the error output and the version of Boost you're using would help a lot. – Luc Danton Aug 03 '12 at 18:32
  • @LucDanton Added the error as part of the question, I'm new to this web site, so apologies if I'm breaking any protocols in forum posting etequette. – Sak Aug 06 '12 at 08:13
  • @LucDanton Tried boost::lambda::bind which seems to compile ok. – Sak Aug 06 '12 at 09:01
0

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; });
karadoc
  • 2,641
  • 22
  • 21