Как подключиться к boost :: signal с помощью общей функции / слота?

Можно ли подключить функцию с другой сигнатурой к Boost :: Signal, который ожидает определенную сигнатуру?

У меня много сигналов (разной сигнатуры). И извне этого модуля я хочу иметь возможность наблюдать за сигналами, не заботясь о сигнатуре сигналов. Это вообще возможно?

Пример:

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);

Можно ли для этого использовать Boost :: Bind?

Используемая версия Boost: 1.46.1

Если я использую

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

Я получаю следующие ошибки:

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

Большое спасибо, ребята.


person Sak    schedule 03.08.2012    source источник


Ответы (2)


Да:

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

Bind просто не пересылает аргументы.

РЕДАКТИРОВАТЬ: Как упоминал Люк, это не сработает из-за того, что выражение привязки ничего не возвращает, возможно, есть другое решение, использующее только привязку ускорения, но другое - выявить большие пушки, boost::phoenix (#include "boost/phoenix.hpp"):

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

Обратите внимание на дополнительный (), иначе вы все равно будете передавать параметры в connect.

person Ylisar    schedule 03.08.2012
comment
Есть вопрос о возвращаемом типе и значении. - person Luc Danton; 03.08.2012
comment
Спасибо за быстрый ответ, у меня возникают ошибки компиляции. Если я вызываю sig.connect ((boost :: phoenix :: bind (& signal_monitor), 1.f)); // Возвращаем 1.f, и все ошибки зашифрованы (как обычно;)) boost / function / function_template.hpp: 132: 42: error: «* f» не может использоваться как функция - person Sak; 03.08.2012
comment
@ user1574205 Приведенный пример можно заставить работать, поэтому вам нужно предоставить дополнительную информацию. Например. ссылка на сообщение об ошибке и версию Boost, которую вы используете, очень помогут. - person Luc Danton; 03.08.2012
comment
@LucDanton Добавил ошибку как часть вопроса, я новичок на этом веб-сайте, поэтому извиняюсь, если я нарушаю какие-либо протоколы в этикете размещения сообщений на форуме. - person Sak; 06.08.2012
comment
@LucDanton Пробовал boost :: lambda :: bind, который, похоже, компилируется нормально. - person Sak; 06.08.2012

Я ожидал, что запрещено использовать функцию, которая возвращает void, вместо функции, которая должна возвращать float; потому что, если возвращаемое значение действительно используется для чего-то, тогда значение будет неопределенным, и поэтому поведение программы может оказаться непредсказуемым.

Поэтому я почти уверен, что единственный способ сделать то, что вы пытаетесь сделать, - это создать новую функцию с правильной подписью, а затем заставить эту функцию просто вызвать вашу функцию void и вернуть 0. Я думаю, что в C ++ 11 это будет работать:

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