Шаблон Boost :: Bind для автоматической обработки нескольких аргументов для функции-члена - PullRequest
3 голосов
/ 19 августа 2010

У меня есть класс с функцией «Attach», который принимает объект функции и сохраняет его в коллекции.Сам класс основан на сигнатуре функции.Примерно так:

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

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

Спасибо.

Редактировать: оказывается, мне здесь не нужно 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?

Ответы [ 2 ]

2 голосов
/ 19 августа 2010

Перегрузка 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 функций-членов, вам понадобится второй набор перегрузок.

2 голосов
/ 19 августа 2010

Создание 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);
...