как boost :: function и boost :: bind работают - PullRequest
81 голосов
/ 09 февраля 2009

Мне не нравится, когда магические блоки разбросаны по всему коду ... как именно работают эти два класса, чтобы позволить в принципе любой функции отображаться на объект функции, даже если функция <> имеет совершенно другой параметр, установленный на один я перехожу к boost::bind

Он даже работает с различными соглашениями о вызовах (то есть методы-члены __thiscall под VC, но "нормальные" функции обычно __cdecl или __stdcall для тех, которые должны быть совместимы с C.

1 Ответ

94 голосов
/ 09 февраля 2009

boost::function разрешает связывать с параметром operator() все что угодно с правильной подписью, а результат вашего связывания можно вызывать с параметром int, поэтому он может быть связан с function<void(int)>.

Вот как это работает (это описание относится к std::function):

boost::bind(&klass::member, instance, 0, _1) возвращает объект, подобный этому

struct unspecified_type
{
  ... some members ...
  return_type operator()(int i) const { return instance->*&klass::member(0, i);
}

где return_type и int выводятся из сигнатуры klass::member, а указатель функции и связанный параметр фактически хранятся в объекте, но это не важно

Теперь boost::function не выполняет никакой проверки типов: он возьмет любой объект и любую сигнатуру, указанную в его параметре шаблона, и создаст объект, который может быть вызван в соответствии с вашей подписью, и вызовет объект. Если это невозможно, это ошибка компиляции.

boost::function на самом деле такой объект:

template <class Sig>
class function
{
  function_impl<Sig>* f;
public:
  return_type operator()(argument_type arg0) const { return (*f)(arg0); }
};

, где return_type и argument_type извлекаются из Sig, а f динамически выделяется в куче. Это необходимо для того, чтобы позволить совершенно несвязанным объектам разных размеров связываться с boost::function.

function_impl это просто абстрактный класс

template <class Sig>
class function_impl
{
public:
  virtual return_type operator()(argument_type arg0) const=0;
};

Класс, который выполняет всю работу, является конкретным классом, производным от boost::function. Существует один для каждого типа объекта, который вы назначаете boost::function

template <class Sig, class Object>
class function_impl_concrete : public function_impl<Sig>
{
  Object o
public:
  virtual return_type operator()(argument_type arg0) const=0 { return o(arg0); }
};

Это означает, что в вашем случае назначение для функции повышения:

  1. создает экземпляр типа function_impl_concrete<void(int), unspecified_type> (это, конечно, время компиляции)
  2. создает новый объект этого типа в куче
  3. назначает этот объект f члену boost :: function

Когда вы вызываете объект функции, он вызывает виртуальную функцию своего объекта реализации, которая направит вызов вашей исходной функции.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: обратите внимание, что имена в этом объяснении специально составлены. Любое сходство с реальными людьми или персонажами ... вы это знаете. Цель состояла в том, чтобы проиллюстрировать принципы.

...