як працює boost :: function і boost :: bind


83

Мені не подобається, що магічні коробки розкидані по всьому моєму коді ... як саме працюють ці два класи, щоб дозволити в основному будь-яку функцію бути зіставленою з об'єктом функції, навіть якщо функція <> має зовсім інший параметр, встановлений на той, який їм передається boost::bind

Він навіть працює з різними конвенціями викликів (тобто методи-члени __thiscallпід VC, але "звичайні" функції, як правило, __cdeclабо __stdcallдля тих, які повинні бути сумісними з C.



1
не зовсім - це питання стосується прив'язки та функції
1800 ІНФОРМАЦІЯ

Так, і тому це все ще залишає питання про те, як можна прив’язати карту void MyClass: DoSomething (std :: string str, int number) до boost :: function <void (int)> через bind (& MyClass :: DoSomething, екземпляр, "Hello Світ ", _1)
Fire Lancer

2
20 000 відвідувань святої корови, це повинно бути на першій сторінці підвищення !
unixman83

Відповіді:


96

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 ::

Коли ви викликаєте об'єкт функції, він викликає віртуальну функцію об'єкта його реалізації, яка направить виклик до вашої вихідної функції.

ЗАМОВЛЕННЯ: Зверніть увагу, що імена в цьому поясненні свідомо вигадані. Будь-яка схожість із реальними особами чи персонажами ... ви це знаєте. Метою було проілюструвати принципи.


так чи вміст struct unspecified_type (тобто код у функції operator ()) в основному генерується з аргументів past to boost :: bind для кожного окремого випадку, щоб дозволити будь-яку комбінацію та кількість аргументів?
Fire Lancer

1
Ні, є шаблони оператора (), які обробляють усі сутності (а різні аргументи шаблону обробляють комбінації)
jpalecek

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

Мені слід трохи пояснити своє запитання: чистому віртуальному можна надати тіло, коли воно оголошено з =0;тілом, наведеним пізніше (наприклад, void Base::Blah() { /* ... */ }) ... Я конкретно запитую про позначення, використані вище; Я здогадуюсь це просто друкарська помилка.
Брайан Ванденберг,

@BrianVandenberg: Я думаю, що це відповідає стандартам, хоча цілком безглуздо.
Mooing Duck
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.