boost :: bind с функциями-членами (в качестве обработчика асинхронной записи boost :: asio)

Я использую boost :: bind для передачи функции-обработчика boost :: asio :: async_write. Когда я использую бесплатные функции, все работает нормально, но когда я пытаюсь переместить функции в класс, связывание приводит к ошибкам, которые я не могу расшифровать.

Что работает:

Я пишу некоторые данные с:

boost::asio::async_write(*socket,
boost::asio::buffer(data(),
length()),
boost::bind(handlermessagewrite,
boost::asio::placeholders::error,
this,
boost::asio::placeholders::bytes_transferred));

Затем я обрабатываю запись свободной функцией, подпись которой:

void handlermessagewrite(const boost::system::error_code& errorcode,
iodata *msg,
size_t bytes_transferred);

Это все работает, как ожидалось.

Что я пытаюсь сделать:

Я перемещаю обработчик внутри класса ioclient:

class ioclient {
public:
void handlermessagewrite(const boost::system::error_code& errorcode,
iodata *msg,
size_t bytes_transferred);
}

void ioclient::handlermessagewrite(const boost::system::error_code& errorcode,
iodata *msg,
size_t bytes_transferred);

и соответственно адаптируем код boost :: bind, как видно из официальных руководств asio:

- boost::bind(handlermessagewrite,

+ boost::bind(&ioclient::handlermessagewrite,

Тем не менее, это приводит к очень непрозрачным ошибкам компиляции, чему не помогает тот факт, что одна из строк в моей IDE обрезается (code :: blocks):

\ Подталкивание \ привязывать \ bind_template.hpp | 102 | требуется от ‘boost :: _ bi :: bind_t :: result_type boost :: _ bi :: bind_t :: operator () (const A1&, const A2&) [с A1 = boost :: system :: error_code; A2 = без знака int; R = пустота; F = повышение :: _ mfi :: mf2; L = boost :: _ bi :: list3 (*) (), boost :: _ bi :: value, boost :: arg<2> (*) ()>; boost :: _ bi :: bind_t :: result_type = void] ‘|
\ Подталкивание \ ASIO \ осущ \ write.hpp | 261 | требуется от ‘void boost :: asio :: detail :: write_op :: operator () (const boost :: system :: error_code&, std :: size_t, int) [с AsyncWriteStream = boost :: asio :: basic_stream_socket; CompletionCondition = boost :: asio :: detail :: Transfer_all_t; WriteHandler = boost :: _ bi :: bind_t, boost :: _ bi :: list3 (*) (), boost :: _ bi :: va |
\ Подталкивание \ ASIO \ осущ \ write.hpp | 585 | требуется от ‘void boost :: asio :: async_write (AsyncWriteStream&Const ConstBufferSequence&, WriteHandler&&) [with AsyncWriteStream = boost :: asio :: basic_stream_socket; ConstBufferSequence = boost :: asio :: mutable_buffers_1; WriteHandler = boost :: _ bi :: bind_t, boost :: _ bi :: list3 (*) (), boost :: _ bi :: value, boost :: arg<2> (*) ()>>] ‘|
\ Iodata.cpp | 76 | требуется отсюда |
\ boost \ bind \ bind.hpp | 392 | ошибка: нет совпадения для вызова ‘(boost :: _ mfi :: mf2) (const boost :: system :: error_code&, йодата *&const без знака int&) ‘|
\ boost \ bind \ mem_fn_template.hpp | 253 | Примечание: кандидаты: |
\ boost \ bind \ mem_fn_template.hpp | 278 | примечание: R boost :: _ mfi :: mf2 :: operator () (T *, A1, A2) const [с R = void; Т = иоклиент; A1 = const boost :: system :: error_code&; A2 = йодата *] |
\ boost \ bind \ mem_fn_template.hpp | 278 | примечание: неизвестное преобразование для аргумента 1 из ‘const boost :: system :: error_code’ в ‘ioclient *’ |
\ boost \ bind \ mem_fn_template.hpp | 283 | примечание: шаблон R boost :: _ mfi :: mf2 :: operator () (U&, A1, A2) const [с U = U; R = пустота; Т = иоклиент; A1 = const boost :: system :: error_code&; A2 = йодата *] |
\ boost \ bind \ mem_fn_template.hpp | 283 | note: сбой вывода / замены аргумента шаблона: |
\ boost \ bind \ bind.hpp | 392 | примечание: невозможно преобразовать ‘(& а) -> повышение :: _ би :: :: песни2 оператор [] ((* &((boost :: _ bi :: list3 (*) (), boost :: _ bi :: value, boost :: arg<2> () ()>) это) -> boost :: _ bi :: list3 (*) (), boost :: _ bi :: value, boost :: arg<2> (*) ()> ::. Boost :: _ bi :: storage3 (*) (), boost :: _ bi :: value, boost :: arg<2> (*) ()> ::. Boost :: _ bi :: storage2 (*) (), boost ::bi :: value> :: a2)) ‘(введите’ iodata * ‘) для ввода’ const boost :: system :: |
\ boost \ bind \ mem_fn_template.hpp | 291 | примечание: шаблон R boost :: _ mfi :: mf2 :: operator () (const U&, A1, A2) const [с U = U; R = пустота; Т = иоклиент; A1 = const boost :: system :: error_code&; A2 = йодата *] |
\ boost \ bind \ mem_fn_template.hpp | 291 | примечание: не удалось вывести / заменить аргумент шаблона: |
\ boost \ bind \ bind.hpp | 392 | примечание: невозможно преобразовать ‘(& а) -> повышение :: _ би :: :: песни2 оператор [] ((* &((boost :: _ bi :: list3 (*) (), boost :: _ bi :: value, boost :: arg<2> () ()>) это) -> boost :: _ bi :: list3 (*) (), boost :: _ bi :: value, boost :: arg<2> (*) ()> ::. Boost :: _ bi :: storage3 (*) (), boost :: _ bi :: value, boost :: arg<2> (*) ()> ::. Boost :: _ bi :: storage2 (*) (), boost ::bi :: value> :: a2)) ‘(введите’ iodata * ‘) для ввода’ const boost :: system :: |
\ boost \ bind \ mem_fn_template.hpp | 299 | примечание: R boost :: _ mfi :: mf2 :: operator () (T&, A1, A2) const [с R = void; Т = иоклиент; A1 = const boost :: system :: error_code&; A2 = йодата *] |
\ boost \ bind \ mem_fn_template.hpp | 299 | примечание: неизвестное преобразование для аргумента 1 из ‘const boost :: system :: error_code’ в ‘ioclient&«|

Я убежден, что я делаю что-то не так с bind, но я не знаю, что это может быть. Есть идеи?

2

Решение

При использовании метода экземпляра вы должны передать this указатель в качестве второго аргумента для bind ().

РЕДАКТИРОВАТЬ:

Я сделал то, что вы пытаетесь сделать с boost :: asio. Вот фрагмент из моей реализации:

        boost::asio::async_write(
m_Socket,
boost::asio::buffer((const unsigned char *)(rMsg.c_str()), rMsg.length()),
boost::bind(&ServerToClientConnT::HandleAsioWrite,
this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));

где HandleAsioWrite — метод, объявленный следующим образом:

void HandleAsioWrite(const boost::system::error_code& rErrorCode,
std::size_t nBytesTransferred);
4

Другие решения

Исходный пример терпит неудачу, потому что экземпляр объекта, для которого будет вызываться функция-член, не передается bind, Это указывается в ошибке компилятора, где говорится, что нет известного преобразования из const boost::system::error_code в ioclient*,

Когда используешь Boost.Bind с указателями членов, это задокументировано, что

boost::bind(&X::f, args) эквивалентно boost::bind<R>(boost::mem_fn(&X::f), args),

Более того, Boost.mem_fnДокументация гласит:

Это [boost::mem_fn] поддерживает указатели на функции-члены с более чем одним аргументом, и возвращаемый объект-функция может принимать указатель, ссылку или умный указатель на экземпляр объекта в качестве первого аргумента.

Таким образом, если этот первый аргумент boost::bind это указатель на член, то либо:

  • Второй аргумент в вызове bind должен быть дескриптором экземпляра объекта, так как он будет первым аргументом, переданным объекту функции, возвращенному из boost::mem_fn,
  • Объект функции вернулся из boost::bind должен быть передан дескриптор экземпляра объекта в позиции аргумента, соответствующей _1 заполнитель.

Например, учитывая

struct Foo
{
void do_something(int x) {}
};

do_something Функция-член может быть связана и вызываться с любым из следующих действий:

Foo f;
boost::bind(&Foo::do_something, &f, _1)(42);     // handle is second argument.
boost::bind(&Foo::do_something, _1, _2)(&f, 42); // handle matches _1 position.
boost::bind(&Foo::do_something, _2, _1)(42, &f); // handle matches _1 position.

С Boost.Asio, boost::asio::placeholders::error реализован как заполнитель _1, По этой причине экземпляр объекта должен быть передан bind Вызовите в качестве второго аргумента, или экземпляр объекта должен быть передан в качестве аргумента либо свободной функции, либо статической функции-члену, которая затем вызовет функцию-член для экземпляра объекта. Вот пример решения, которое компилируется с нестатической функцией-членом, но фрагмент интересов:

ioclient client;
iodata data;

boost::asio::async_write(
socket,
boost::asio::null_buffers(),
boost::bind(&ioclient::handlermessagewrite,
&client,
boost::asio::placeholders::error,
&data,
boost::asio::placeholders::bytes_transferred));

ошибка компилятора опубликовано в ответ на Лу указывает на то, что ioclient функция-член пытается быть вызвана с дескриптором экземпляра iodataнесовместимый тип. За iodata чтобы быть совместимым типом, он должен быть унаследован от ioclient, Если это предполагаемая иерархия типов, проверьте правильность наследования. В противном случае тщательно сопоставьте типы аргументов и позиции с привязываемой функцией.

3