Как использовать boost::bind в роли аргумента?

Я читаю статью: <br/> <a href="https://habr.com/ru/articles/192284/" rel="nofollow">https://habr.com/ru/articles/192284/</a> <br/> <br/> и наткнулся на следующий код: <pre><code class="cpp">void start_accept(socket_ptr sock) { acc.async_accept(*sock, boost::bind(handle_accept, sock, _1)); } void handle_accept(socket_ptr sock, const boost::system::error_code &amp; err) { if (err) return; // здесь можно читать/писать с сокета socket_ptr sock(new ip::tcp::socket(service)); start_accept(sock); }</code></pre> <br/> <br/> Мне непонятно, как работает функция bind. <br/> <br/> Во втором аргументе используется плейсхолдер, но там должен быть аргумент типа boost::system::error_code. <br/> <br/> Как именно вызывается объект, который является результатом бинда? Я видел примеры вроде следующего: <br/> <pre><code class="cpp">auto f = boost::bind(function, _1, _1); f(1, 2); // фактически вызывается function(1, 1);</code></pre> <br/> Я понимаю принцип работы плейсхолдера (он подставляет соответствующий по порядку аргумент в функцию там, где расположен плейсхолдер). <br/> <br/> Но в данном случае мы просто передаем объект в асинхронную функцию. Какие аргументы получает обертка? Неужели обертка вызывается таким образом f() без аргументов, и если это так, то какое значение имеет плейсхолдер в этом примере?
  • 27 августа 2024 г. 21:04
Ответы на вопрос 1
Разберем, как работает `boost::bind` в приведенном вами коде и как он связан с использованием плейсхолдера `_1`.

### Основы `boost::bind`

`boost::bind` — это утилита, позволяющая связывать аргументы с функциями или методами, создавая новый объект, который можно вызывать. Например, если у вас есть функция, которая принимает несколько аргументов, и вы хотите фиксировать некоторые из них, `boost::bind` позволяет сделать это.

### Пример кода

Теперь давайте рассмотрим ваш код:

```cpp
void start_accept(socket_ptr sock) {
    acc.async_accept(*sock, boost::bind(handle_accept, sock, _1));
}

void handle_accept(socket_ptr sock, const boost::system::error_code & err) {
    if (err) return;
    socket_ptr sock(new ip::tcp::socket(service));
    start_accept(sock);
}
```

### Как это работает

1. **Вызов `async_accept`:** Функция `acc.async_accept` инициирует асинхронное принятие соединения на сокете `*sock`. Этот метод ожидает, что после завершения операции будет вызвана указанная обработка, которая передается как аргумент.

2. **Использование `boost::bind`:** Когда мы вызываем `boost::bind(handle_accept, sock, _1)`, мы создаем объект, который будет "обертывать" функцию `handle_accept`. Первый аргумент (это `sock`) фиксируется, а второй аргумент — это плейсхолдер `_1`, который будет заменен на первый аргумент, который будет передан в `handle_accept` независимой операцией асинхронного принятия.

3. **Как вызывается обертка:** Вызов `async_accept` по завершении асинхронной операции вызовет обработчик и передаст в него объект ошибки (типа `boost::system::error_code`). Это означает, что в момент вызова, если, к примеру, произошла ошибка, это значение будет передано в `handle_accept`. 

### Результат

Когда возникнет событие, после асинхронного завершения операции, произойдет следующее:

- `handle_accept` будет вызван с первым аргументом, установленным в значение `sock` (которое было зафиксировано при создании бинда).
- Второй аргумент (ошибка) будет передан из аргументов `async_accept` (это значение будет находиться на месте `_1`).

Таким образом, ваш обработчик будет правильно получать в себя оба необходимых значения — сокет и объект ошибки.

### Заключение

Итак, плейсхолдеры необходимы для того, чтобы указать, где именно в вызываемой функции должны подставляться параметры при моментальном вызове. В вашем случае `_1` подставляется в обработчик как результат данной асинхронной операции (в данном случае, объект ошибки).
Похожие вопросы