2010-08-19 1 views
3

У меня есть класс с функцией «Прикрепить», которая принимает объект функции и сохраняет его в коллекции. Сам класс затенен на подпись функции. Что-то вроде этого:Templating boost :: bind для автоматической обработки нескольких аргументов для функции-члена

template<class Signature> 
class Event 
{ 
public: 

void Attach(boost::function<Signature> signature) 
{ 
    MySignatures.push_back(signature); 
} 

private: 

std::list<boost::function<Signature>> MySignatures; 
}; 

Чтобы продемонстрировать использование, рассмотрим следующий класс:


class Listening 
{ 
public: 

int SomeFunction(int x, int y, int z); 
}; 

Чтобы передать функцию на Listening в Event, я должен был бы написать:


Event<int(int, int, int)> myEvent; 
Listening myListening; 

myEvent.Attach(boost::bind(boost::mem_fn(&Listening::SomeFunction), &myListening, _1, _2, _3)); 

Так вместо этого для каждого случая, который может быть подвержен ошибкам, я пишу набор макросов следующим образом:


#define EventArgument0(x, y) boost::bind(boost::mem_fn(x), y) 
#define EventArgument1(x, y) boost::bind(boost::mem_fn(x), y, _1) 
#define EventArgument2(x, y) boost::bind(boost::mem_fn(x), y, _1, _2) 
#define EventArgument3(x, y) boost::bind(boost::mem_fn(x), y, _1, _2, _3) 
#define EventArgument4(x, y) boost::bind(boost::mem_fn(x), y, _1, _2, _3, _4) 

etc. 

и тогда я могу написать:


myEvent.Attach(EventArgument3(&Listening::SomeFunction, &myListening)); 

, который намного легче читать (я думаю). Теперь мой вопрос: как я могу вместо этого написать:


myEvent.Attach(EventArgument(&Listening::SomeFunction, &MyListening)); 

или даже лучше:


myEvent.Attach(&Listening::SomeFunction, &myListening); 

, так что событие Приложить волшебно связать правильно с соответствующим количеством аргументов, содержащихся в < Подпись > (в этом примере, int(int, int, int))? Я открыт для любого шаблона мета-программирования, который вы имеете в виду здесь.

Спасибо.

Edit: оказывается, мне не нужно boost::mem_fn здесь, потому что boost::bind эквивалентно, поэтому в моем макрос можно использовать:

bind(&MyClass::Hello, myClass, _1, _2, _3); 

, вместо:

bind(mem_fn(&MyClass::Hello), myClass, _1, _2, _3); 

Вопрос остается: как передать &MyClass::Hello классу событий и использовать перегрузку шаблона для обработки _1, _2, _3 и т. д., подразумеваемых прототипом функции, используемой для шаблона Event класс?

+0

Вы пытались использовать Google/Bing для «идеальной пересылки»? Предположим, вы можете использовать C++ 0x. – Henrik

+0

Я сейчас смотрю на это, например здесь: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm. Мне непонятно, как это помогает решить проблему. – Robinson

ответ

2

перегрузка Attach для различного числа параметров в функции члена:

template<typename R,typename T,typename U> 
void Attach(R (T::*pmf)(),U* p)) 
{ 
    Attach(boost::bind(pmf,p)); 
} 

template<typename R,typename T,typename U,typename A1> 
void Attach(R (T::*pmf)(A1),U* p)) 
{ 
    Attach(boost::bind(pmf,p,_1)); 
} 

template<typename R,typename T,typename U,typename A1,typename A2> 
void Attach(R (T::*pmf)(A1,A2),U* p)) 
{ 
    Attach(boost::bind(pmf,p,_1,_2)); 
} 

Если вам нужно обрабатывать const функции члена тоже тогда вам нужен второй набор перегрузок.

+0

Блестящий. Я немного изменил его для работы с shared_ptr (поэтому я могу удерживать ссылки weak_ptr и останавливать указатели .expired() перед отключением события). В противном случае это отличное решение. Благодарю. – Robinson

2

Attach() шаблон позволит вам сделать то, к чему вы стремитесь. Код становится грязным, но он позволяет вам называть его так, как вы хотите.

template<typename A1> 
void Attach(A1 a1); 

template<typename A1, typename A2> 
void Attach(A1 a1, A2 a2); 

template<typename A1, typename A2, typename A3> 
void Attach(A1 a1, A2 a2, A3 a3); 

template<typename A1, typename A3, typename A4> 
void Attach(A1 a1, A2 a2, A3 a3, A4 a4);