Как создать boost :: function из шаблона подписи - PullRequest
1 голос
/ 23 июля 2011

Недавно я пытался создать гибкую реализацию шаблона наблюдателя, которая скрывает 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 Ответ

0 голосов
/ 23 июля 2011

Нет, 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 может уже иметь такой шаблон преобразования, но я не смог его найти.

...