Namespaces
Variants

std:: bind

From cppreference.net
Utilities library
Function objects
Function invocation
(C++17) (C++23)
Identity function object
(C++20)
Old binders and adaptors
( until C++17* )
( until C++17* )
( until C++17* )
( until C++17* )
( until C++17* ) ( until C++17* ) ( until C++17* ) ( until C++17* )
( until C++20* )
( until C++20* )
( until C++17* ) ( until C++17* )
( until C++17* ) ( until C++17* )

( until C++17* )
( until C++17* ) ( until C++17* ) ( until C++17* ) ( until C++17* )
( until C++20* )
( until C++20* )
Определено в заголовке <functional>
template < class F, class ... Args >
/* unspecified */ bind ( F && f, Args && ... args ) ;
(1) (начиная с C++11)
(constexpr начиная с C++20)
template < class R, class F, class ... Args >
/* unspecified */ bind ( F && f, Args && ... args ) ;
(2) (начиная с C++11)
(constexpr начиная с 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 , поведение не определено.

Связанные аргументы

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

Случай 1: reference wrappers

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

Случай 2: выражения bind

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

Случай 3: placeholders

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

Случай 4: обычные аргументы

В противном случае, arg_i передается вызываемому объекту как lvalue-аргумент: v_i является просто arg_i , а его тип V_i — это T cv  & , где 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 ) на объект, член которого будет доступен.

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

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

Пример

#include <functional>
#include <iostream>
#include <memory>
#include <random>
void f(int n1, int n2, int n3, const int& 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()
{
    using namespace std::placeholders;  // для _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) вложенные bind-выражения разделяют плейсхолдеры: ";
    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) привязать генератор случайных чисел к распределению: ";
    std::default_random_engine e;
    std::uniform_int_distribution<> d(0, 10);
    auto rnd = std::bind(d, e); // копия e сохраняется в rnd
    for (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::данные, _1);
    std::cout << f5(foo) << '\n';
    std::cout << "8) привязка к mem_fn, которая является указателем на член данных: ";
    auto ptr_to_data = std::mem_fn(&Foo::данные);
    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) вложенные подвыражения bind разделяют плейсхолдеры: 12 12 12 4 5
4) привязка ГСЧ к распределению: 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++.

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

Смотрите также

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