2009-02-09 6 views
80

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

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

+0

Dupe: http://stackoverflow.com/questions/112738/how-does-boost-bind-work-behind-the-scenes-in-general –

+1

не очень - этот вопрос связан с привязкой и функцией –

+0

Да и таким образом, все еще остается вопрос о том, как связать map void MyClass: DoSomething (std :: string str, int number) для boost :: function через bind (& MyClass :: DoSomething, instance, «Hello World», _1) –

ответ

94

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. присваивает этот объект дзета члена повышения :: функция

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

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

+0

, так же как и содержимое struct unspecified_type (т.е. код в функции operator()), базово генерируемый из аргументов прошлого, для boost :: bind на основе каждого случая, чтобы разрешить любую комбинацию и количество аргументов? –

+1

Нет, есть шаблоны оператора(), которые обрабатывают все arities (и разные аргументы шаблона обрабатывают комбинации) – jpalecek

+0

В последнем блоке кода он читает: 'arg0) const = 0 {return ...' ... Я никогда не видел этого раньше. Я нашел один неработающий пример в форуме, где последующее сообщение, связанное с C++ faq, объясняющее, что чистая виртуальная функция может иметь тело, но я не могу получить какой-либо код для компиляции с использованием такого синтаксиса (clang & gcc). –