Пространства имён
Варианты
Действия

std::bind

Материал из cppreference.com
< cpp‎ | utility‎ | functional
 
 
Библиотека утилит
Языковая поддержка
Поддержка типов (базовые типы, RTTI)
Макросы тестирования функциональности библиотеки (C++20)    
Управление динамической памятью
Программные утилиты
Поддержка сопрограмм(C++20)
Вариативные функции
Трёхстороннее сравнение (C++20)
(C++20)
(C++20)(C++20)(C++20)(C++20)(C++20)(C++20)
Общие утилиты
Дата и время
Функциональные объекты
Библиотека форматирования(C++20)
(C++11)
Операторы отношения (устарело в C++20)
Целочисленные функции сравнения
(C++20)(C++20)(C++20)    
(C++20)
Операции обмена и типа
(C++11)
(C++11)
(C++17)
Общие лексические типы
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)
Элементарные преобразования строк
(C++17)
(C++17)
 
Объекты функции
Функции обёртки
(C++11)
(C++11)
Применение частичных функций
(C++20)(C++23)
bind
(C++11)
Вызов функции
(C++17)(C++23)
Объект идентичности функции
(C++20)
Обёртки ссылок
(C++11)(C++11)
Прозрачные обёртки операторов
(C++14)
(C++14)
(C++14)
(C++14)  
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)
Отрицатели
(C++17)
Искатели
Ограниченные компараторы
Старые привязки и адаптеры
(до C++17*)
(до C++17*)
(до C++17*)
(до C++17*)
(до C++17*)(до C++17*)(до C++17*)(до C++17*)
(до C++20*)
(до C++20*)
(до C++17*)(до C++17*)
(до C++17*)(до C++17*)

(до C++17*)
(до C++17*)(до C++17*)(до C++17*)(до C++17*)
(до C++20*)
(до C++20*)
 
Определено в заголовочном файле <functional>
(1)
template<class F, class... Args>
/*не определено*/ bind( F&& f, Args&&... args);
(начиная с C++11)
(до C++20)
template<class F, class... Args>
constexpr/*не определено*/ bind( F&& f, Args&&... args);
(начиная с C++20)
(2)
template<class R, class F, class... Args>
/*не определено*/ bind( F&& f, Args&&... args);
(начиная с C++11)
(до C++20)
template<class R, class F, class... Args>
constexpr/*не определено*/ bind( F&& f, Args&&... args);
(начиная с C++20)

Шаблон функции std::bind создает оболочку переадресации вызовов для f. Вызов этой оболочки эквивалентен вызову f с некоторыми аргументами, привязанными к args.

Если std::is_constructible<std::decay<F>::type, F>::value равно false или std::is_constructible<std::decay<Arg_i>::type, Arg_i>::value равно false для любого типа Arg_i в Args, программа некорректна.

Если std::decay<Ti>::type или любой тип в Args не является MoveConstructible или Destructible, поведение не определено.

Содержание

[править]Параметры

f объект Callable (объект функции, указатель на функцию, ссылка на функцию, указатель на функцию-элемент или указатель на элемент данных), который будет привязан к некоторым аргументам
args список аргументов для привязки, где несвязанные аргументы заменены заполнителями_1, _2, _3... пространства имён std::placeholders

[править]Возвращаемое значение

Объект функции g неопределённого типа T для которого std::is_bind_expression<T>::value равно true. В него входят следующие элементы:

std::bindвозвращаемый тип

Объекты-элементы

Тип возвращаемого значения std::bind содержит объект-элемент типа std::decay<F>::type, созданный из std::forward<F>(f) и по одному объекту на каждый из args... типа std::decay<Arg_i>::type, аналогично созданному из std::forward<Arg_i>(arg_i).

Конструкторы

Тип возвращаемого значения std::bind является CopyConstructible, если все его объекты-элементы (указанные выше) являются CopyConstructible, и MoveConstructible иначе. Тип определяет следующие элементы:

Тип элемент result_type

1)(устарело в C++17) Если F является указателем на функцию или указателем на функцию-элемент, result_type является возвращаемым типом F. Если F является типом класса с вложенным typedef result_type, то result_type является F::result_type. Иначе result_type не определён.
2)(устарело в C++17)result_type является точно R.
(до C++20)

Функция элемент operator()

Когда g вызывается в выражении вызова функции g(u1, u2, ... uM), происходит вызов сохраненного объекта, как если бы

1)INVOKE(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN)), или
2)INVOKE<R>(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN)),

где fd это значение типа std::decay<F>::type, значения и типы связанных аргументов v1, v2, ..., vN определяются, как указано ниже.

Если некоторые из аргументов, предоставленных при вызове g(), не совпадают ни с одним заполнителем, хранящимся в g, неиспользуемые аргументы оцениваются и отбрасываются.

Вызов operator() это не генерирует исключениели является константным подвыражением(начиная с C++20) если и только если такова базовая операция INVOKE. operator() участвует в разрешении перегрузки только в том случае, если операция INVOKE имеет правильный формат при обработке как невычисленного операнда.

Если g является volatile-квалифицированным, программа некорректна.

Если INVOKE(fd, w1, w2, ..., wN) никогда не может быть допустимым выражением для любых возможных значений w1, w2, ..., wN, поведение не определено.

[править]Привязанные аргументы

В операции INVOKE или INVOKE<R> Для каждого сохранённого аргумента arg_i определяется соответствующий связанный аргумент v_i следующим образом:

[править]Случай 1: обёртки ссылок

Если arg_i имеет тип std::reference_wrapper<T> (например, std::ref или std::cref использовались при первоначальном вызове std::bind), тогда v_i равно arg_i.get() и его тип V_i равен T&: сохранённый аргумент передаётся по ссылке в вызываемый функциональный объект.

[править]Случай 2: выражения привязки

Если arg_i имеет тип T, для которого std::is_bind_expression<T>::value имеет значение true (например, другое выражение std::bind было передано непосредственно в начальный вызов std::bind), тогда std::bind выполняет композицию функций: вместо передачи функционального объекта, который будет возвращён подвыражением привязки, подвыражение с готовностью вызывается, и его возвращаемое значение передаётся внешнему вызываемому объекту. Если подвыражение привязки имеет какие-либо аргументы-заполнители, они используются совместно с внешней привязкой (выбранной из u1, u2, ...). В частности, v_i это arg_i(std::forward<Uj>(uj)...), а его тип V_i есть std::result_of<Tcv &(Uj&&...)>::type&&(до C++17)std::invoke_result_t<Tcv &, Uj&&...>&&(начиная с C++17) (cv-квалификация такая же, как у g).

[править]Случай 3: заполнители

Если arg_i имеет тип T, для которого std::is_placeholder<T>::value не является 0 (это означает, что заполнитель, такой как std::placeholders::_1, _2, _3, ..., использовался в качестве аргумента для начального вызова std::bind), тогда аргумент, указанный заполнителем (u1 для _1, u2 для _2 и.д.), передаётся вызываемому объекту: v_i это std::forward<Uj>(uj), а его тип V_i это Uj&&.

[править]Случай 4: обычные аргументы

Иначе arg_i передаётся вызываемому объекту в качестве аргумента lvalue: v_i просто arg_i, а его тип V_i равен Tcv &, где cv та же самая cv-квалификация, что и у g.

[править]Исключения

Генерируется, только если создание std::decay<F>::type из std::forward<F>(f) генерирует исключения, или если любой из конструкторов для std::decay<Arg_i>::type из соответствующего std::forward<Arg_i>(arg_i) генерирует исключения, где Arg_i i-й тип, а arg_i i-й аргумент в Args... args.

[править]Примечание

Как описано в Callable, при вызове указателя на нестатическую функцию-элемент или указателя на нестатический элемент данных первый аргумент должен быть ссылкой или указателем (включая, возможно, умный указатель, такой как std::shared_ptr и std::unique_ptr) на объект, элемент которого будет доступен.

Аргументы для привязки копируются или перемещаются и никогда не передаются по ссылке, если только они не заключены в std::ref или std::cref.

Повторяющиеся заполнители в одном и том же выражении привязки (например, несколько _1) допускаются, но результаты корректно определены только в том случае, если соответствующий аргумент (u1) является lvalue или не перемещаемое rvalue.

[править]Пример

#include <functional>#include <iostream>#include <memory>#include <random>   void f(int n1, int n2, int n3, constint& n4, int n5){std::cout<< n1 <<' '<< n2 <<' '<< n3 <<' '<< n4 <<' '<< n5 <<'\n';}   int g(int n1){return n1;}   struct Foo {void print_sum(int n1, int n2){std::cout<< n1+n2 <<'\n';}int data =10;};   int main(){usingnamespacestd::placeholders;// for _1, _2, _3...   std::cout<<"1) переупорядочивание аргументов и передача по ссылке: ";int n =7;// (_1 и _2 взяты из std::placeholders, и представляют// будущие аргументы, которые будут переданы в f1)auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n); n =10; f1(1, 2, 1001);// 1 связан с _1, 2 связан с _2, 1001 не используется// вызывает f(2, 42, 1, n, 7)   std::cout<<"2) достижение того же эффекта с помощью лямбда: "; n =7;auto lambda =[&ncref=n, n](auto a, auto b, auto/*не используется*/){ f(b, 42, a, ncref, n);}; n =10; lambda(1, 2, 1001);// то же, что и вызов f1(1, 2, 1001)   std::cout<<"3) вложенные подвыражения связывания совместно используют заполнители: ";auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5); f2(10, 11, 12);// вызывает f(12, g(12), 12, 4, 5);   std::cout<<"4) связывает RNG с распределением: ";std::default_random_engine e;std::uniform_int_distribution<> d(0, 10);auto rnd = std::bind(d, e);// копия e хранится в rndfor(int n=0; n<10;++n)std::cout<< rnd()<<' ';std::cout<<'\n';   std::cout<<"5) привязка к указателю на функцию-элемент: "; Foo foo;auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1); f3(5);   std::cout<<"6) привязка к mem_fn, который является указателем на функцию-элемент: ";auto ptr_to_print_sum =std::mem_fn(&Foo::print_sum);auto f4 = std::bind(ptr_to_print_sum, &foo, 95, _1); f4(5);   std::cout<<"7) привязка к указателю на элемент данных: ";auto f5 = std::bind(&Foo::data, _1);std::cout<< f5(foo)<<'\n';   std::cout<<"8) привязка к mem_fn, который является указателем на элемент данных: ";auto ptr_to_data =std::mem_fn(&Foo::data);auto f6 = std::bind(ptr_to_data, _1);std::cout<< f6(foo)<<'\n';   std::cout<<"9) использует умные указатели для вызова элементов по ссылке ""на объекты: ";std::cout<< f6(std::make_shared<Foo>(foo))<<' '<< f6(std::make_unique<Foo>(foo))<<'\n';}

Вывод:

1) переупорядочивание аргументов и передача по ссылке: 2 42 1 10 7 2) достижение того же эффекта с помощью лямбда: 2 42 1 10 7 3) вложенные подвыражения связывания совместно используют заполнители: 12 12 12 4 5 4) связывает RNG с распределением: 0 1 8 5 5 2 0 7 7 10 5) привязка к указателю на функцию-элемент: 100 6) привязка к mem_fn, который является указателем на функцию-элемент: 100 7) привязка к указателю на элемент данных: 10 8) привязка к mem_fn, который является указателем на элемент данных: 10 9) использует умные указатели для вызова элементов по ссылке на объекты: 10 10

[править]Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

Номер Применён Поведение в стандарте Корректное поведение
LWG 2021 C++11 1. привязанные аргументы
    не были переправлены в fd
2. в случае 2, тип V_i был
    std::result_of<Tcv (Uj...)>::type
1. переправлены
2. изменён на
    std::result_of<Tcv &(Uj&&...)>::type&&

[править]Смотрите также

(C++20)(C++23)
связывает переменное количество аргументов по порядку с объектом функцией
(шаблон функции)[править]
заполнители для несвязанных аргументов в выражении std::bind
(константа)[править]
(C++11)
создаёт объект функцию из указателя на элемент
(шаблон функции)[править]
close