Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.80/5: Рейтинг темы: голосов - 5, средняя оценка - 4.80
1 / 1 / 0
Регистрация: 06.05.2021
Сообщений: 242

Как работает std::bind?

11.10.2024, 19:08. Показов 1217. Ответов 11
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Приветствую. Вопрос собственно в следующем: как я понял placeholders в bind указывает какой аргумент взять при вызове из оператора скобки и посдатвить в функцию. Т.е bind(f, 2222, placeholders::_2)(3333, 4444);, здесь если placeholders::_2, то это равносильно f(2222, 4444), а если placeholders::_1, то равносильно f(2222, 3333); В коде ниже есть функция f(int, int) и пример бинда с ней.
Но, так же в примере есть класс Base с методом show(), который аргументов вообще не принимает и в мэйне for_each(v.begin(), v.end(), bind(&Base::show, placeholders::_1));, но тогда мне не понятно, для чего используется placeholders::_1 в случае когда аругументов у функции, которая отправляется в бинд нету? И получается, с помощью бинда можно создавать функтор как с большим количеством аргументов, чем у изначальной функции, так и с меньшим?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#include <functional>
#include <vector>
 
using namespace std;
 
class Base 
{
public:
    void show()
    {
        cout << "Base" << endl;
    }
};
 
////////////////////////////////////////////////////////////////////////////////////////////////////////
 
double my_divide(double x, double y) { return x / y; };
 
////////////////////////////////////////////////////////////////////////////////////////////////////////
 
void f(int x, int y)
{
    cout << "x = " << x << '\n';
    cout << "y = " << y << '\n';
}
 
int main()
{
    vector<Base*>v{ new Base{},new Base{} };
    for_each(v.begin(), v.end(), bind(&Base::show, std::placeholders::_1));
 
    auto fn_half = std::bind(my_divide, std::placeholders::_1, 2);               // returns x/2
    std::cout << fn_half(10) << '\n';
 
    bind(f, std::placeholders::_1, std::placeholders::_2)(15, 10);
    bind(f, std::placeholders::_2, std::placeholders::_1)(15, 10);
    bind(f, std::placeholders::_1, 100)(150);
    bind(f, std::placeholders::_2, 1000)(222, 1500);
    bind(f, 2222, std::placeholders::_2)(3333, 4444);
 
    system("pause");
    return 0;
}
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
11.10.2024, 19:08
Ответы с готовыми решениями:

Как можно еще использовать std::placeholders вне в связки с std::bind?
Добрый день! Как можно еще использовать std::placeholders вне в связки с std::bind?

Std::bind, std::mem_fun, std::mem_fn
В чем разница между функциями std::bind, std::mem_fun, std::mem_fn?

Накладные расходы std::function, std::bind, анонимные функции
Здравствуйте, Позвольте два вопроса: 1)Подскажите пожалуйста, вот на таком просто примере: int my_func(double db_,...

11
87 / 87 / 18
Регистрация: 11.06.2018
Сообщений: 302
11.10.2024, 19:11
Цитата Сообщение от Ballantrae Посмотреть сообщение
Но, так же в примере есть класс Base с методом show(), который аргументов вообще не принимает и в мэйне for_each(v.begin(), v.end(), bind(&Base::show, placeholders::_1));, но тогда мне не понятно, для чего используется placeholders::_1?
Для this.
1
Заблокирован
11.10.2024, 19:36
Цитата Сообщение от Ballantrae Посмотреть сообщение
И получается, с помощью бинда можно создавать функтор как с большим количеством аргументов, чем у изначальной функции, так и с меньшим?
Если аргументов больше, они игнорируются.

Добавлено через 13 минут
Цитата Сообщение от Ballantrae Посмотреть сообщение
И получается, с помощью бинда можно создавать функтор как с большим количеством аргументов, чем у изначальной функции, так и с меньшим?
Да.
0
1 / 1 / 0
Регистрация: 06.05.2021
Сообщений: 242
11.10.2024, 19:44  [ТС]
Цитата Сообщение от SmallEvil Посмотреть сообщение
Если аргументов больше, они игнорируются.
Если добавить в for_each(v.begin(), v.end(), bind(&Base::show, placeholders::_1)) placeholders::_2, то не будет компилироваться.
0
Заблокирован
11.10.2024, 20:06
Цитата Сообщение от Ballantrae Посмотреть сообщение
Если добавить в for_each(v.begin(), v.end(), bind(&Base::show, placeholders::_1)) placeholders::_2, то не будет компилироваться.
Я про другой случай. Если в функтор от bind передать больше параметров (не меньше, как вы привели), то они будут игнорироваться.

Добавлено через 3 минуты
bind - это конструкт, который создает функтор, в его конструкторе описываются сами связи.

C++
1
2
3
4
   auto f = [](int a){};
   auto binded_f = std::bind(f, 5);
   binded_f(); // OK
   binded_f(1, 2, 3); // olso ok, unused
Добавлено через 12 минут
Пример с большим количеством аргументов :
C++
1
2
3
4
   using namespace std::placeholders;
   auto f = [](int a){};
   auto binded_f= std::bind(f, _3);
   binded_f(1, 2, 3); // 1, 2 - unused
Добавлено через 1 минуту
И ещё :
C++
1
2
3
4
5
   using namespace std::placeholders;
   auto f = [](int a){ std::cout << a << std::endl;};
   auto c = [](int a, int b, int c){ return a + b + c;};
   auto binded_more_arg = std::bind(f, std::bind(c, _1, _2, _3));
   binded_more_arg(1, 2, 3);
1
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12928 / 6796 / 1819
Регистрация: 18.10.2014
Сообщений: 17,197
11.10.2024, 23:09
Лучший ответ Сообщение было отмечено Ballantrae как решение

Решение

Цитата Сообщение от Ballantrae Посмотреть сообщение
Вопрос собственно в следующем: как я понял placeholders в bind указывает какой аргумент взять при вызове из оператора скобки и посдатвить в функцию. Т.е bind(f, 2222, placeholders::_2)(3333, 4444);, здесь если placeholders::_2, то это равносильно f(2222, 4444),
Да, если вам именно такое нужно, то есть если вы хотите именно "выхватить" второй аргумент из предоставленного набора и проигнорировать все остальные. Наверное в 99% случаев std::bind используют так, чтобы у результирующего функтора был компактный и непрерывный (с точки зрения нумерации) набор аргументов. Но если вам приспичило заняться именно "выхватыванием" отдельных разрозненных аргументов из избыточного набора - то так тоже можно.

Цитата Сообщение от Ballantrae Посмотреть сообщение
но тогда мне не понятно, для чего используется placeholders::_1 в случае когда аругументов у функции, которая отправляется в бинд нету?
У функции Base::show() в вашем примере есть параметр. В этом случае функция является нестатическим методом класса, а это значит, что с точки зрения std::bind ее первый параметр - это указатель this. То есть у нее есть неявный параметр Base *this. Именно в него и будет передаваться аргумент, обозначенный placeholders::_1 в вашем случае. Если бы у show были явные параметры, то они бы являлись вторым, третьим и т.д. параметрами.

То есть вашем примере bind(&Base::show, std::placeholders::_1) фактически "ничего не делает", кроме того, что превращает/конвертирует метод класса (т.е. функцию с неявным параметром) в функтор с одним явным параметром. "Фиксации" каких-то параметров не происходит вообще: как был один параметр, так и остался. Но теперь такой функтор может вызываться обычным синтаксисом вызова функции, а не специальным синтаксисом вызова метода класса.

У полученного в результате функтора есть еще одно замечательное свойство: в качестве аргумента он может принимать как указатель, так и ссылку. В обоих случаях он правильно вызовет метод:

C++
1
2
3
4
5
6
7
8
9
10
int main()
{
  auto bbb = std::bind(&Base::show, std::placeholders::_1);
    
  std::vector<Base *> vp = { new Base{}, new Base{} };
  std::for_each(vp.begin(), vp.end(), bbb);
 
  std::vector<Base> vb(2);
  std::for_each(vb.begin(), vb.end(), bbb);
}
Добавлено через 39 минут
Цитата Сообщение от Ballantrae Посмотреть сообщение
Если добавить в for_each(v.begin(), v.end(), bind(&Base::show, placeholders::_1)) placeholders::_2, то не будет компилироваться.
Что именно "не будет компилироваться"?

Никаких проблем с bind(&Base::show, placeholders::_2) нет. Все прекрасно компилируется, не надо выдумывать.

А "не будет компилироваться" - это если позже, в точке вызова функтора, вы укажете аргументов меньше, чем нужно. О каком "втором аргументе" может идти речь, если в точке вызова вы указали только один аргумент? Неудивительно, что вызов не будет компилироваться.

В точке вызова можно указывать больше аргументов, чем нужно. Но указывать меньше, чем нужно, нельзя.
0
 Аватар для Наталья8
518 / 368 / 65
Регистрация: 09.03.2016
Сообщений: 3,890
11.10.2024, 23:26
https://habr.com/ru/articles/310270/
А я ни чё не понял. Вы все умные, а я не очень.
Помню я извращённый синтаксис boost...
Я что то даже изобретал на нём. Клиент-сервер.

Добавлено через 9 минут
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/////////////////////////////////////////////////////////////// SERVER ///// Принимает данные ////////////////////////////////////
int main(int argc, char* argv[])
     {
    ip::tcp::endpoint ep(ip::tcp::v4(), 2001); // listen on 2001
    ip::tcp::acceptor acc(service, ep);
    std::cout << " =============== Server  ===============" << std::endl;
//------------------------- 
 
    while (true) {
        socket_ptr sock(new ip::tcp::socket(service));
                acc.accept(*sock);// <------------------- Сервер здесь висит
        boost::thread(boost::bind(client_session, sock) );// Отработавший поток рассыпался. Это другой
                 }
    std::cout <<" press any key "<< std::endl;
    _getch();
    return 0;
     }
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12928 / 6796 / 1819
Регистрация: 18.10.2014
Сообщений: 17,197
12.10.2024, 03:13
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
То есть вашем примере bind(&Base::show, std::placeholders::_1) фактически "ничего не делает", кроме того, что превращает/конвертирует метод класса (т.е. функцию с неявным параметром) в функтор с одним явным параметром.
... и так как это часто необходимая функциональность, для нее есть и специальный шаблон std::mem_fn. То есть вместо такого bind можно было написать намного короче - std::mem_fn(&Base::show) - и получить тот же самый эффект.
0
1 / 1 / 0
Регистрация: 06.05.2021
Сообщений: 242
12.10.2024, 11:50  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Никаких проблем с bind(&Base::show, placeholders::_2) нет. Все прекрасно компилируется, не надо выдумывать.
А "не будет компилироваться" - это если позже, в точке вызова функтора, вы укажете аргументов меньше, чем нужно. О каком "втором аргументе" может идти речь, если в точке вызова вы указали только один аргумент? Неудивительно, что вызов не будет компилироваться.
Речь о bind(&Base::show, placeholders::_1, placeholders::_2). Но выше уже пояснили на этот счёт.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12928 / 6796 / 1819
Регистрация: 18.10.2014
Сообщений: 17,197
12.10.2024, 19:45
Цитата Сообщение от Ballantrae Посмотреть сообщение
Речь о bind(&Base::show, placeholders::_1, placeholders::_2).
Я как то не уловил, что bind(&Base::show, placeholders::_1)) placeholders::_2 - это bind(&Base::show, placeholders::_1, placeholders::_2)

В любом случае, подытоживая, если говорить о соответствии количества параметров, то проверки времени компиляции сводятся к следующему:

1. В точке выполнения std::bind количество указанных подстановок для параметров должно быть равно количеству параметров используемой функции. То есть для каждого параметра (включая неявный this) должно быть указано либо связывающее значение, либо placeholder, либо вложенный bind.

2. В точке вызова количество указанных аргументов должно быть не меньше чем максимальный номер использованного placeholder.

При этом если задача состоит просто в том, чтобы, как в вашем примере с Base::show, превратить метод класса в обычный функтор (не манипулируя параметрами), то std::mem_fn для этой цели пользоваться удобнее, ибо в нем вообще не нужно думать о параметрах.

Хотя во время выполнения и std::mem_fn, и std::bind будут менее эффективными, чем лямбда в той же роли.
1
1 / 1 / 0
Регистрация: 06.05.2021
Сообщений: 242
14.10.2024, 12:40  [ТС]
TheCalligrapher, спасибо, суть вроде уловил. Хотя не всё ещё понятно. У меня в рабочем коде используется boost log, и написан класс, который должен то что выводится в лог, выводить так же и в виджет внутри программы. Рабочий код я показать не могу, но я написал аналогичный кусок, что бы повторить в упрощённом виде, без буста, рабочий код и разобраться как он работает. Тут не всё, что в рабочем коде, там ещё используется boost::shared_ptr<logger_boost_notifier_ t> ptr = boost::make_shared<logger_boost_notifier _t>(tb_ptr)Но так как я без буста хотел повторить часть кода, то этой строки у меня нет. Вот он:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
typedef std::function<void(const std::string& str)> str_print_callback;
 
class TestBase
{
public:
    TestBase(const str_print_callback& callback = nullptr) : callback_(callback) {};
 
    void consume(std::string const& message)
    {
        if (callback_ != nullptr) callback_(message);
    }
 
private:
    str_print_callback callback_ = nullptr;
};
 
class TestPrint
{
public:
    TestPrint()
    {
        tb_ptr = boost::make_shared<TestBase>(bind(&TestPrint::print_log_str, this, std::placeholders::_1));
    }
    ~TestPrint() {}
private:
    boost::shared_ptr<TestBase> tb_ptr = nullptr;
 
    void print_log_str(std::string str)
    {
        std::cout << str << std::endl;
    }
};
Как я понял, задумка заключается в том, что бы через переменную callback_ класса TestBase, вызывать метод print_log_str класса TestPrint. У меня возникает несколько вопросов:
1) Что происходит в строке tb_ptr = boost::make_shared<TestBase>(bind(&TestP rint:rint_log_str, this, std:laceholders::_1)); (никак не разберусь, как выделять строку с кодом в тексте)
Тут я присваиваю значение tb_ptr, это понятно. Но как возврат бинда превращается в shared_ptr (я не про make_shared), а про то - что bind возвращает? Объект функтор наверно ведь? Но как он может в итоге стать shared_ptr да ещё и на другой класс?
2) Зачем явно передаётся this?
3) В бинд я передаю указатель на функцию, но ведь имя функции это и есть указатель на неё, по этому мне не понятно, почему перед TestPrint:rint_log_str мне нужно указывать &?
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12928 / 6796 / 1819
Регистрация: 18.10.2014
Сообщений: 17,197
14.10.2024, 20:03
Цитата Сообщение от Ballantrae Посмотреть сообщение
Но как возврат бинда превращается в shared_ptr (я не про make_shared), а про то - что bind Нвозвращает? Объект функтор наверно ведь? Но как он может в итоге стать shared_ptr да ещё и на другой класс?
(Не понимаю вашей ремарки "я не про make_shared". У вас в коде shared_ptr создается только через make_shared. Больше нигде.)

make_shared<T> создает объект типа T, то есть именно того типа, который указан в треугольных скобках. То есть ваш boost::make_shared<TestBase> создает объект типа TestBase и возвращает shared_ptr именно на новый объект типа TestBase. Не на результат bind, как вы почему-то подумали, а именно на новый объект типа TestBase.

А обычные параметры функции, указанные в круглых скобках, лишь используются в качестве параметров конструктора для создаваемого объекта. То есть в вашем случае результат bind не имеет никакого отношения к shared_ptr и никак в него не "превращается". Результат bind будет просто передан в конструктор создаваемого TestBase. То есть результат bind превратится в std::function<>, т.е. в str_print_callback.

Так работает make_shared.

---

То есть ваше tb_ptr = make_shared<TestBase>(bind(&TestPrint::print_log_str, this, std::placeholders::_1)) - это аналог (по шагам)

C++
1
2
3
4
auto fun = bind(&TestPrint::print_log_str, this, std::placeholders::_1);
str_print_callback cb = fun;
TestBase *tb = new TestBase(cb);
tb_ptr = shared_ptr(tb);
Цитата Сообщение от Ballantrae Посмотреть сообщение
Зачем явно передаётся this?
Ну так, как говорилось выше, TestPrint::print_log_str имеет два параметра: неявный ("невидимый") параметр this и явный параметр str. Нам нужно превратить этот метод в str_print_callback, который имеет один параметр. То есть один параметр нам надо будет исключить ("связать") при помощи bind.

Это мы и делаем.

Первый (неявный) параметр TestPrint::print_log_str мы "связываем" при помощи bind: в качестве аргумента мы подставляем значение this, то есть этот связанный параметр будет указывать на тот самый объект, который создал этот функтор. А второй параметр мы оставляем "свободным". В результате мы получаем функтор с одним параметром, как нам и нужно.

Цитата Сообщение от Ballantrae Посмотреть сообщение
В бинд я передаю указатель на функцию, но ведь имя функции это и есть указатель на неё
Это справедливо только для "обычных" функций, но не для методов классов. Это правило неприменимо к нестатическим методам классов. Указатели на методы классов всегда получаются именно как &Class::method. Все надо явно писать целиком, включая &.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
14.10.2024, 20:03
Помогаю со студенческими работами здесь

В чем отличия между std::cref() и std::bind()?
В документации не понял, что делает bind() ? И чем отличается cref() от операции взятия адреса? int x; int *y = &amp;x;...

std::bind
Можно ли, и если да, то как с помощью этой функции сделать следующее: auto var=std::bind(&amp;f, &quot;arg&quot;); //... //... ...

реализация std::bind
Добрый день, форумчане, Мне интересно как внутренне работает std::bind. Заинтересовало в первую очередь как placeholder заменяется...

std::bind и указатель на функцию
Здравствуйте, Объясните пожалуйста, что то я запутался: -В Первом случае - я по сути просто грубо говоря присваиваю...

Разобраться с std::bind, плейсхолдеры
Здравствуйте, чтобы разобраться с основами std::bind написал следующий код: #include &lt;functional&gt; #include &lt;vector&gt; ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Новые блоги и статьи
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США. Нашел на реддите интересную статью под названием «Кто-нибудь знает, где получить бесплатный компьютер или. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru