![]() |
![]() |
|
|
Вместе с boost::lambda
Author / Автор: Сергей СацкийPublication date / Опубликовано: 26.09.2005
|
void f( const double & Value ) { cout << "f called. Value: " << Value << endl; } |
Сущность реализуем в виде класса с примерно таким интерфейсом:
struct CallbackStorage { CallbackStorage() { . . . } void insert( . . . ) { . . . } void operator() ( const double & val ) { . . . } }; |
Стоит заметить, что весь приводимый здесь код - только набросок, который не следут использовать в промышленном программном обеспечении без существенных изменений. Так, например, структура использована только для несущественного сокращения записи.
Для хранения списка callback функций отлично подойдет std::vector объектов boost::function.
std::vector< boost::function< void ( const double & ) > > v;
|
Реализация члена-функции insert(. . .), обеспечивающего регистрацию callback функции, тривиальна.
void insert( function< void ( const double & ) > func )
{
v.push_back( func );
}
|
Функция-член operator() обеспечит обработку внешнего события, то есть вызов всех зарегистрированных функций с передачей им нового значения.
void operator() ( const double & val )
{
vector< function< void ( const double & ) > >::iterator k;
for ( k = v.begin(); k != v.end(); ++k )
{
(*k)( val );
}
}
|
Конструктор оставим пустым.
Теперь предположим, что подобный код используется в приложении, которое использует множество double переменных и позволяет раздельно регистрировать / дерегистрировать callback функции для каждой из них. Иногда может оказаться удобным не использовать явно написанную callback функцию, а иметь обновленное значение всегда "под рукой". То есть использовать следующую логику - передавать в качестве регистрации не функцию, а ссылку на double переменную, считая что она будет обновлена, как только будет произведено присвоение.
Другими словами потребуется перегруженный вариант функции-члена insert().
void insert( double & Ref ) { . . . }
|
Что делать с переданной ссылкой? Лобовой вариант - хранить еще один список внутри CallbackStorage и в operator() добавить второй цикл, в котором и производить присваивания. Однако этот вариант кажется не очень изящным.
Библиотека boost::lambda позволит избежать хранения еще одного списка и дополнительного цикла. Вторую функцию-член insert(. . .) можно реализовать следующим образом.
void insert( double & Ref )
{
function< void ( const double & ) > g = ( var( Ref ) = _1 );
v.push_back( g );
}
|
Получилось чрезвычайно лаконично!
Исходный код примера можно найти на интернет сайте автора: (http://satsky.spb.ru).