Как boost::function и boost::bind работают
Мне не нравится, когда магические блоки разбросаны по всему коду... как именно работают эти два класса, чтобы позволить в принципе любой функции отображаться на объект функции, даже если функция<> имеет совершенно другой параметр, установленный на тот, который я передаю в boost::bind
Он даже работает с различными соглашениями о вызовах (т.е. __thiscall
под VC, но обычно "нормальные" функции __cdecl
или же __stdcall
для тех, которые должны быть совместимы с C.
1 ответ
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); }
};
В вашем случае это означает назначение функции повышения:
- создает экземпляр типа
function_impl_concrete<void(int), unspecified_type>
(это время компиляции, конечно) - создает новый объект этого типа в куче
- назначает этот объект f члену boost::function
Когда вы вызываете объект функции, он вызывает виртуальную функцию своего объекта реализации, который направит вызов вашей исходной функции.
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Обратите внимание, что имена в этом объяснении специально составлены. Любое сходство с реальными людьми или персонажами... вы это знаете. Цель состояла в том, чтобы проиллюстрировать принципы.