<boost::bind>является обобщением стандартных функций<std::bind1st>и<std::bind2nd>. Он поддерживает произвольные функциональные объекты, функции, указатели функций и указатели функций членов и способен связывать любой аргумент с конкретным значением или маршрутом входных аргументов в произвольные позиции.<bind>не предъявляет никаких требований к объекту функции; в частности, ему не нужны<result_type>,<first_argument_type>и<second_argument_type>стандартные типдефы.
<bind(f,1,2)>будет производить «нулевой» функциональный объект, который не принимает аргументов и возвращает<f(1,2)>. Так же<bind(g,1,2,3)()>эквивалентно<tog(1,2,3)>.
Выборочно можно связать только некоторые аргументы.<bind(f,_1,5)(x)>эквивалентно<f(x,5)>; здесь<_1>—заполнительаргумент, который означает «заменить первым входным аргументом».
Для сравнения, вот та же операция, выраженная со стандартными библиотечными примитивами:
std::bind2nd(std::ptr_fun(f),5)(x);
<bind>охватывает также функциональность<std::bind1st>:
Обратите внимание, что в последнем примере объект функции, произведенный<bind(g,_1,_1,_1)>, не содержит ссылок на какие-либо аргументы, кроме первого, но он все еще может использоваться с более чем одним аргументом. Любые дополнительные аргументы молча игнорируются, как первый и второй аргумент игнорируются в третьем примере.
Аргументы, которые<bind>принимает, копируются и удерживаются внутренним объектом возвращаемой функции. Например, в следующем коде:
inti=5;bind(f,i,_1);
копия значения<i>хранится в объекте функции.<boost::ref>и<boost::cref>можно использовать для того, чтобы объект функции сохранял ссылку на объект, а не копию:
<bind>не ограничивается функциями; принимает произвольные функциональные объекты. В общем случае тип возврата генерируемого функционального объекта<operator()>должен быть определен явно (без оператора<typeof>тип возврата не может быть выведен):
structF{intoperator()(inta,intb){returna-b;}booloperator()(longa,longb){returna==b;}};Ff;intx=104;bind<int>(f,_1,_1)(x);// f(x, x), i.e. zero
Некоторые компиляторы имеют проблемы с синтаксисом<bind<R>(f,...)>. По причинам переносимости поддерживается альтернативный способ выражения вышеизложенного:
boost::bind(boost::type<int>(),f,_1,_1)(x);
Обратите внимание, однако, что альтернативный синтаксис предоставляется только в качестве обходного пути. Он не является частью интерфейса.
Когда объект функции показывает вложенный тип, названный<result_type>, явный тип возврата может быть опущен:
intx=8;bind(std::less<int>(),_1,9)(x);// x < 9
[Примечание:Возможность опустить тип возврата доступна не на всех компиляторах.
По умолчанию<bind>делает копию предоставленного функционального объекта.<boost::ref>и<boost::cref>могут использоваться для хранения ссылки на объект функции, а не на копию. Это может быть полезно, когда объект функции не является копируемым, дорогим для копирования или содержит состояние; конечно, в этом случае ожидается, что программист гарантирует, что объект функции не будет уничтожен, пока он все еще используется.
Указатели на функции-члены и указатели на члены данных не являются функциональными объектами, поскольку они не поддерживают<operator()>. Для удобства<bind>принимает указатели-члены в качестве своего первого аргумента, и поведение таково, как если бы<boost::mem_fn>использовался для преобразования указателя-члена в объект функции. Другими словами, выражение
где<R>- тип возврата<X::f>(для функций члена) или тип члена (для членов данных).
[Примечание:<mem_fn>создает функциональные объекты, которые способны принять указатель, ссылку или умный указатель на объект в качестве первого аргумента; для получения дополнительной информации см. документацию<mem_fn>
Пример:
structX{boolf(inta);};Xx;shared_ptr<X>p(newX);inti=5;bind(&X::f,ref(x),_1)(i);// x.f(i)bind(&X::f,&x,_1)(i);// (&x)->f(i)bind(&X::f,x,_1)(i);// (internal copy of x).f(i)bind(&X::f,p,_1)(i);// (internal copy of p)->f(i)
Последние два примера интересны тем, что они производят «самосодержащиеся» функциональные объекты.<bind(&X::f,x,_1)>хранит копию<x>.<bind(&X::f,p,_1)>хранит копию<p>, и поскольку<p>является<boost::shared_ptr>, объект функции сохраняет ссылку на свой экземпляр<X>и будет оставаться в силе даже тогда, когда<p>выходит за рамки или является<reset()>.
Некоторые из аргументов, переданных<bind>, могут быть вложенысами связывают выражения:
bind(f,bind(g,_1))(x);// f(g(x))
Внутренниесвязывающие выраженияоцениваются в неуказанном порядке перед внешним<bind>при вызове функционального объекта; затем результаты оценки заменяются на их место при оценке внешнего<bind>. В приведенном выше примере, когда объект функции вызывается с помощью списка аргументов<(x)>,<bind(g,_1)(x)>сначала оценивается, получая<g(x)>, а затем<bind(f,g(x))(x)>оценивается, получая конечный результат<f(g(x))>.
Эта особенность<bind>может быть использована для выполнения функциональной композиции. См.bind_as_compose.cppдля примера, который демонстрирует, как использовать<bind>для достижения аналогичной функциональностиBoost.Compose.
Обратите внимание, что первый аргумент - объект связанной функции - не оценивается, даже если это объект функции, который производится аргументом<bind>или, поэтому приведенный ниже пример не работает так, как ожидалось:
Желаемый эффект может быть достигнут посредством объекта функции помощника<apply>, который применяет свой первый аргумент в качестве объекта функции к остальной части своего списка аргументов. Для удобства, реализация<apply>предусмотрена вфайле заголовка application.hpp. Вот как выглядит модифицированная версия предыдущего примера:
Хотя первый аргумент по умолчанию не оценивается, все остальные аргументы являются. Иногда необходимо не оценивать аргументы, следующие за первым, даже когда они вложены, связывают подвыражения. Это может быть достигнуто с помощью другого функционального объекта,<protect>, который маскирует тип так, что<bind>не распознает и не оценивает его. При вызове защитите просто перенаправьте список аргументов на другой неизмененный объект функции.
Заголовокprotect.hppсодержит реализацию<protect>. Для<protect>объекта функции связи из оценки используйте<protect(bind(f,...))>.
Для удобства объекты функции, создаваемые<bind>, перегружают логический, а не оператор<!>и реляционный и логический операторы<==,!=,<,<=,>,>=,&&,||>.
<!bind(f,...)>эквивалентно<bind(logical_not(),bind(f,...))>, где<logical_not>является функциональным объектом, который принимает один аргумент<x>и возвращает<!x>.
<bind(f,...)opx>, гдеopявляется реляционным или логическим оператором, эквивалентно<bind(relation(),bind(f,...),x)>, где<relation>является функциональным объектом, который принимает два аргумента<a>и<b>и возвращает<aopb>.
На практике это означает, что вы можете легко отрицать результат<bind>:
Как правило, объекты функции, порожденные<bind>, берут свои аргументы за основу и, следовательно, не могут принимать временные или буквальные константы. Это неотъемлемое ограничение языка C++ в его нынешнем (2003) воплощении, известное как проблема пересылки. (Это будет исправлено в следующем стандарте, обычно называемом C++0x.)
Библиотека использует подписи формы
template<classT>voidf(T&t);
принимать аргументы произвольных типов и передавать их на немодифицированные. Как уже отмечалось, это не работает с неконстными r-значениями.
На компиляторах, поддерживающих частичную упорядоченность шаблонов функций, возможно решение добавить перегрузку:
К сожалению, это требует 512 перегрузок для девяти аргументов, что непрактично. Библиотека выбирает небольшое подмножество: для двух аргументов она обеспечивает перегрузку const в полном объеме, для удобств трех и более она обеспечивает одну дополнительную перегрузку со всеми аргументами, взятыми ссылкой const. Это охватывает разумную часть случаев использования.
Вероятно, потому, что вы использовали общий синтаксис<bind<R>(f,...)>, тем самым инструктируя<bind>не «инспектировать» f для обнаружения ошибок типа arity и return.
Первая форма предписывает<bind>проверить тип<f>, чтобы определить его аритмию (количество аргументов) и тип возврата. Ошибки Arity будут обнаружены в «связанное время». Этот синтаксис, конечно, предъявляет некоторые требования<f>. Это должна быть функция, указатель функции, указатель функции члена или объект функции, который определяет вложенный тип, названный<result_type>; короче говоря, это должно быть что-то, что<bind>может распознать.
Вторая форма предписывает<bind>не пытаться распознать тип<f>. Обычно он используется с функциональными объектами, которые не выставляют или не могут выставлять<result_type>, но также может использоваться с нестандартными функциями. Например, текущая реализация не распознает автоматически функции с переменными аргументами, такие как<printf>, поэтому вам придется использовать<bind<int>(printf,...)>. Обратите внимание, что альтернативный<bind(type<R>(),f,...)>синтаксис поддерживается по причинам переносимости.
Другим важным фактором, который следует учитывать, является то, что компиляторы без частичной специализации шаблона или поддержки частичного упорядочивания шаблона функции не могут обрабатывать первую форму, когда<f>является объектом функции, и в большинстве случаев не будут обрабатывать вторую форму, когда<f>является функцией (указателем) или указателем функции члена.
Иногда. На некоторых платформах указатели на внешние функции «С» эквивалентны «обычным» указателям функций, поэтому они работают нормально. Другие платформы рассматривают их как разные типы. Ожидается, что реализация<bind>, ориентированная на конкретную платформу, будет решать проблему прозрачно; эта реализация этого не делает. Как обычно, обходной путь состоит в том, чтобы рассматривать функцию какобщий объект функциии использовать синтаксис<bind<R>(f,...)>.
Непортативные расширения, как правило, должны по умолчанию отключаться, чтобы предотвратить блокировку поставщика. Если бысоответствующие макросыбыли определены автоматически, вы могли бы случайно воспользоваться ими, не понимая, что ваш код, возможно, больше не переносим. Кроме того, некоторые компиляторы имеют возможность сделать<__stdcall><__fastcall>своим стандартом вызова по умолчанию, и в этом случае отдельная поддержка не потребуется.
В выражении<bind(f,a1,a2,...,aN)>объект функции<f>должен иметь возможность принимать ровно N аргументов. Эта ошибка обычно обнаруживается в «связанное время»; другими словами, ошибка компиляции сообщается в строке, где<bind()>вызывается:
intf(int,int);intmain(){boost::bind(f,1);// error, f takes two argumentsboost::bind(f,1,2);// OK}
Распространенным вариантом этой ошибки является забывание о том, что функции-члены имеют неявный аргумент «это»:
structX{intf(int);}intmain(){boost::bind(&X::f,1);// error, X::f takes two argumentsboost::bind(&X::f,_1,1);// OK}
Как и в обычных вызовах функции, связанный объект функции должен быть совместим со списком аргументов. Несовместимость обычно обнаруживается компилятором во время вызова, и результатом обычно является ошибка<bind.hpp>в строке, которая выглядит как:
returnf(a[a1_],a[a2_]);
Пример такой ошибки:
intf(int);intmain(){boost::bind(f,"incompatible");// OK so far, no callboost::bind(f,"incompatible")();// error, "incompatible" is not an intboost::bind(f,_1);// OKboost::bind(f,_1)("incompatible");// error, "incompatible" is not an int}
Заполнитель<_N>выбирает аргумент в позиции<N>из списка аргументов, прошедшего в «время вызова». Конечно, попытка выйти за пределы этого списка является ошибкой:
intf(int);intmain(){boost::bind(f,_1);// OKboost::bind(f,_1)();// error, there is no argument number 1}
Ошибка обычно сообщается в<bind.hpp>, в строке, аналогичной:
returnf(a[a1_]);
При эмуляции<std::bind1st(f,a)>распространенной ошибкой этой категории является тип<bind(f,a,_2)>вместо правильного<bind(f,a,_1)>.
Форма<bind(f,a1,a2,...,aN)>вызывает автоматическое распознавание типа<f>. Он не будет работать с произвольными функциональными объектами;<f>должен быть функцией или указателем функции члена.
Можно использовать эту форму с функциональными объектами, определяющими<result_type>, но только на компиляторах, поддерживающих частичную специализацию и частичную упорядоченность. В частности, MSVC до версии 7.0 не поддерживает этот синтаксис для функциональных объектов.
Можно (но не рекомендуется) использовать эту форму с функциями или указателями функций членов, но только на компиляторах, поддерживающих частичную упорядоченность. В частности, MSVC до версии 7.0 не полностью поддерживает этот синтаксис для функций и указателей функций членов.
По умолчанию<bind(f,a1,a2,...,aN)>формараспознает «обычные» функции C++ и указатели функций.Функции, использующие другую конвенцию вызовов, или функции с переменными аргументами, такие как<std::printf>, не работают. Общая<bind<R>(f,a1,a2,...,aN)>формаработает с нестандартными функциями.
На некоторых платформах внешние функции «С», такие как<std::strcmp>, не распознаются короткой формой<bind>.
Попытка связать перегруженную функцию обычно приводит к ошибке, поскольку нет способа определить, какая перегрузка должна быть связана. Это общая проблема с функциями-членами с двумя перегрузками, как в этом упрощенном примере:
Объекты функций, которые производятся<bind>, не моделируют понятия STLУнарная функцияилиБинарная функция, даже когда объекты функций являются унарными или двоичными операциями, потому что типы объектов функций не имеют общедоступных типовых значений<result_type>и<argument_type>или<first_argument_type>и<second_argument_type>. Однако в тех случаях, когда эти типдефы желательны, функция полезности<make_adaptable>может быть использована для адаптации объектов унарной и двоичной функций к этим понятиям. Это позволяет комбинировать объекты унарных и двоичных функций, полученные из<bind>, с шаблонами STL, такими как<std::unary_negate>и<std::binary_negate>.
В этом примере<bind>создаётся «пространство» (унитарный) предикат. Затем он передается<make_adaptable>так, что функция объекта моделирует.Унарная функцияможет быть создана как аргумент<std::not1>.
На MSVC (до версии 7.0), когда<boostbind>приведен в действие с помощью декларации:
usingboost::bind;
Синтаксис<bind<R>(f,...)>не работает. Обратная сторона: либо используйте квалифицированное имя<boost::bind>, либо используйте вместо этого директиву использования:
На MSVC (до версии 7.0) вложенный шаблон класса под названием<bind>будет затенять шаблон функции<boost::bind>, нарушая синтаксис<bind<R>(f,...)>. К сожалению, некоторые библиотеки содержат вложенные шаблоны классов, названные<bind>(по иронии судьбы, такой код часто является специфическим обходным путем MSVC).
Для этого используется альтернативный синтаксис<bind(type<R>(),f,...)>.
MSVC (до версии 7.0) рассматривает эллипс в переменной функции аргумента (например,<std::printf>) как тип. Поэтому он примет (неправильную в текущей реализации) форму:
namespaceboost{// no argumentstemplate<classR,classF>unspecified-1bind(Ff);template<classF>unspecified-1-1bind(Ff);template<classR>unspecified-2bind(R(*f)());// one argumenttemplate<classR,classF,classA1>unspecified-3bind(Ff,A1a1);template<classF,classA1>unspecified-3-1bind(Ff,A1a1);template<classR,classB1,classA1>unspecified-4bind(R(*f)(B1),A1a1);template<classR,classT,classA1>unspecified-5bind(R(T::*f)(),A1a1);template<classR,classT,classA1>unspecified-6bind(R(T::*f)()const,A1a1);template<classR,classT,classA1>unspecified-6-1bind(RT::*f,A1a1);// two argumentstemplate<classR,classF,classA1,classA2>unspecified-7bind(Ff,A1a1,A2a2);template<classF,classA1,classA2>unspecified-7-1bind(Ff,A1a1,A2a2);template<classR,classB1,classB2,classA1,classA2>unspecified-8bind(R(*f)(B1,B2),A1a1,A2a2);template<classR,classT,classB1,classA1,classA2>unspecified-9bind(R(T::*f)(B1),A1a1,A2a2);template<classR,classT,classB1,classA1,classA2>unspecified-10bind(R(T::*f)(B1)const,A1a1,A2a2);// implementation defined number of additional overloads for more arguments}namespace{unspecified-placeholder-type-1_1;unspecified-placeholder-type-2_2;unspecified-placeholder-type-3_3;// implementation defined number of additional placeholder definitions}
Всенеопределенные-Nтипы, возвращаемые<bind>, являютсяCopyConstructible.неопределенные-N<::result_type>определяется как тип возвратанеопределенные-N<::operator()>.
Все типынеуказанных держателей-NявляютсяCopyConstructible. Их конструкторы копий не бросают исключений.
Примечания:Осуществления допускаются для вывода о типе возврата<f>с помощью других средств в качестве расширения без использования элемента<result_type>.
template<classR>unspecified-2bind(R(*f)())
Возвращает:Объект функции λ такой, что выражение λ<(v1,v2,...,vm)>эквивалентно<f()>.
Примечания:Осуществления допускаются для вывода о типе возврата<f>с помощью других средств в качестве расширения без использования элемента<result_type>.
Возвращение:Объект функции λ такой, что выражение λ<(v1,v2,...,vm)>эквивалентно<f(>μ<(a1,v1,v2,...,vm),>μ<(a2,v1,v2,...,vm))>, неявно преобразовано в<R>.
Броски:Ничего, кроме того, что создатели копий<F>,<A1>или<A2>не делают исключения.
Примечания:Осуществления допускаются для вывода о типе возврата<f>с помощью других средств в качестве расширения без использования элемента<result_type>.
Некоторые платформы допускают несколько типов (член) функций, которые отличаются по своей конвенции вызова (правила, по которым функция вызывается: как передаются аргументы, как обрабатывается возвращаемое значение и кто очищает стек - если таковой имеется).
Например, функции API Windows и функции членов интерфейса COM используют соглашение вызова, известное как<__stdcall>. Компоненты Borland VCL используют<__fastcall>. Функции набора инструментов Mac используют конвенцию вызова<pascal>.
Для использования<bind>с<__stdcall>функциями<#define>макрос<BOOST_BIND_ENABLE_STDCALL>перед включением<<boost/bind.hpp>>.
Для использования<bind>с функциями<__stdcall>,<#define>макрос<BOOST_MEM_FN_ENABLE_STDCALL>перед включением<<boost/bind.hpp>>.
Чтобы использовать<bind>с<__fastcall>функциями,<#define>макрос<BOOST_BIND_ENABLE_FASTCALL>перед включением<<boost/bind.hpp>>.
Для использования<bind>с функциями<__fastcall>,<#define>макрос<BOOST_MEM_FN_ENABLE_FASTCALL>перед включением<<boost/bind.hpp>>.
Для использования<bind>с<pascal>функциями<#define>макрос<BOOST_BIND_ENABLE_PASCAL>перед включением<<boost/bind.hpp>>.
Для использования<bind>с функциями<__cdecl>,<#define>макрос<BOOST_MEM_FN_ENABLE_CDECL>перед включением<<boost/bind.hpp>>.
Лучше всего определить эти макросы в параметрах проекта, через<-D>в командной строке или в качестве первой строки в блоке перевода (файл .cpp), где<bind>используется.Несоблюдение этого правила может привести к неясным ошибкам, когда заголовок включает<bind.hpp>до того, как был определен макрос.
[Примечание:это непортативное расширение. Он не является частью интерфейса.
[Примечание:Некоторые компиляторы обеспечивают только минимальную поддержку ключевого слова<__stdcall>.
Многочисленные улучшения были предложены в течение формального периода обзора Россом Смитом, Ричардом Кроссли, Йенсом Маурером, Эдом Бреем и другими. Менеджером по обзору был Дарин Адлер.
Точная семантика<bind>была доработана в дискуссиях с Jaakko Järvi.
Дэйв Абрахамс изменил<bind>и<mem_fn>для поддержки<void>возвратов на недостающие компиляторы.
Мак Мюрретт внес вклад в «паскальную» поддержку<BOOST_BIND_ENABLE_PASCAL>.
Альтернативный синтаксис<bind(type<R>(),f,...)>был вдохновлен дискуссией с Дэйвом Абрахамсом и Джоэлом де Гусманом.
Эта документация была портирована на Quickbook Agustín Bergé.
Последний пересмотр: 21 сентября 2016 года в 14:46:28 GMT
Статья Chapter 1. Boost.Bind раздела Chapter 1. Boost.Bind может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.