Spec-Zone.ru › C++

std::bind

Определено в заголовке <functional>
(1)
template< class F, class... Args >
/* unspecified */ bind( F&& f, Args&&... args );
(с C++11)
(до C++20)
template< class F, class... Args >
constexpr /* unspecified */ bind( F&& f, Args&&... args );
(с C++20)
(2)
template< class R, class F, class... Args >
/* unspecified */ bind( F&& f, Args&&... args );
(с C++11)
(до C++20)
template< class R, class F, class... Args >
constexpr /* unspecified */ 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 - Список аргументов для привязки, при этом несвязанные аргументы заменяются плейсхолдерами placeholders _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, то неиспользуемые аргументы вычисляются и отбрасываются.

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

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

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

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

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

Случай 1: обёртки ссылок

Если arg_i имеет тип std::reference_wrapper<T> (например, std::ref или std::cref использовались в начальном вызове std::bind), то 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: плейсхолдеры

Если 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 является 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) на объект, члены которого будут обработаны.

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

Позволяется дублировать заполнительные места в одном выражении привязки (например, несколько _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;  // for _1, _2, _3...
 
    std::cout << "1) argument reordering and pass-by-reference: ";
    int n = 7;
    // (_1 and _2 are from std::placeholders, and represent future
    // arguments that will be passed to f1)
    auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);
    n = 10;
    f1(1, 2, 1001); // 1 is bound by _1, 2 is bound by _2, 1001 is unused
                    // makes a call to f(2, 42, 1, n, 7)
 
    std::cout << "2) achieving the same effect using a lambda: ";
    n = 7;
    auto lambda = [&ncref = n, n](auto a, auto b, auto /*unused*/)
    {
        f(b, 42, a, ncref, n);
    };
    n = 10;
    lambda(1, 2, 1001); // same as a call to f1(1, 2, 1001)
 
    std::cout << "3) nested bind subexpressions share the placeholders: ";
    auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
    f2(10, 11, 12); // makes a call to f(12, g(12), 12, 4, 5);
 
    std::cout << "4) bind a RNG with a distribution: ";
    std::default_random_engine e;
    std::uniform_int_distribution<> d(0, 10);
    auto rnd = std::bind(d, e); // a copy of e is stored in rnd
    for (int n = 0; n < 10; ++n)
        std::cout << rnd() << ' ';
    std::cout << '\n';
 
    std::cout << "5) bind to a pointer to member function: ";
    Foo foo;
    auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
    f3(5);
 
    std::cout << "6) bind to a mem_fn that is a pointer to member function: ";
    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) bind to a pointer to data member: ";
    auto f5 = std::bind(&Foo::data, _1);
    std::cout << f5(foo) << '\n';
 
    std::cout << "8) bind to a mem_fn that is a pointer to data member: ";
    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) use smart pointers to call members of the referenced objects: ";
    std::cout << f6(std::make_shared<Foo>(foo)) << ' '
              << f6(std::make_unique<Foo>(foo)) << '\n';
}

Вывод:

1) argument reordering and pass-by-reference: 2 42 1 10 7
2) achieving the same effect using a lambda: 2 42 1 10 7
3) nested bind subexpressions share the placeholders: 12 12 12 4 5
4) bind a RNG with a distribution: 0 1 8 5 5 2 0 7 7 10 
5) bind to a pointer to member function: 100
6) bind to a mem_fn that is a pointer to member function: 100
7) bind to a pointer to data member: 10
8) bind to a mem_fn that is a pointer to data member: 10
9) use smart pointers to call members of the referenced objects: 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&&

См. также

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

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/utility/functional/bind

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API