Как создать boost::function из шаблона подписи
Недавно я пытался создать гибкую реализацию шаблона наблюдателя, которая скрывает boost::signal
, Я почти преуспел.
у меня есть Observer
класс, который должен иметь update
сигнатура соответствия метода, предоставленная параметром шаблона.
Пример использования:
Observable<void(float, float)> observable;
Observer<void(float, float)> observer;
observable.attach(&observer);
observable.notify(Observable::Arguments(10.0f, 1.0f)); // invokes observer->update(10.0f, 1.0f);
Все работает просто отлично, если observer
не перегружен update
метод. В таком случае boost::bind
не может вывести правильный метод для использования. К сожалению, я не могу использовать явное приведение, потому что я не знаю аргументов обновления (эта информация находится в FunctionSignature
).
Следующий метод вызывает проблемы:
class Observable <typename FunctionSignature>
{
...
template <class DerivedObserverClass>
void attach(DerivedObserverClass* observer)
{
STATIC_ASSERT((boost::is_base_of<ObserverType, DerivedObserverClass>::value));
ConnectionsMap::iterator it = connections.find(observer);
if (it == connections.end() || !it->second.connected()) {
// i would like to do something like
// boost::function<FunctionSignature> f;
// f = boost::bind(&static_cast<FunctionSignature>DerivedObserverClass::update, observer, _1);
// singnalSlot is defined as boost::signal<FunctionSignature>
// this works as long, as Derived class doesn't have overloaded update method
connections[observer] = signalSlot.connect(boost::bind(&DerivedClass::update, observer, _1));
} else {
throw std::invalid_argument("Observer already attached.");
}
}
я думаю что boost::function
может помочь решить эту проблему. Я не знаю, как связать это с правильным методом члена, используя только подпись шаблона.
Это вообще возможно?
1 ответ
Нет, boost::function вам тоже не поможет. 13.4.3 говорит
Нестатические функции-члены соответствуют целям типа "указатель на член-функцию"; тип функции указателя на член используется для выбора функции-члена из набора перегруженных функций-членов.
Это означает, что вы не можете взять адрес перегруженной функции-члена, передать его какому-либо объекту функции (шаблонному или нет, boost или std или как угодно) и надеяться, что перегрузка разрешится сама собой. Вам нужен подлинный честный тип указатель на функцию-член в левой части назначения.
Вам придется конвертировать ваши FunctionSignature
как-то к указателю на тип функции-члена. Вот немного старомодной магии шаблонов, которая делает то, что вам нужно, для ограниченного числа аргументов функций. C++0x может иметь лучшее, более общее решение.
template <typename C, typename F>
struct tomemfun;
template <typename C, typename res>
struct tomemfun<C, res()>
{
typedef res (C::*memfun_t)();
};
template <typename C, typename res, typename arg1>
struct tomemfun<C, res(arg1)>
{
typedef res (C::*memfun_t)(arg1);
};
template <typename C, typename res, typename arg1, typename arg2>
struct tomemfun<C, res(arg1, arg2)>
{
typedef res (C::*memfun_t)(arg1, arg2);
};
// repeat with more arguments as needed
Теперь вы можете использовать
tomemfun<DerivedClass, FunctionSignature>::memfun_t update = &DerivedClass::update;
и он разрешит справа перегруженную функцию.
boost
возможно, уже есть такой шаблон преобразования, но я не смог его найти.