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) [with 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&, iodata*&, const unsigned 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| примечание: не удалось вывести / заменить аргумент шаблона:| \boost\bind\bind.hpp|392| примечание: невозможно преобразовать '(& a)->boost::_bi::list2::operator[]((* &((boost::_bi::list3 (*)) (), boost:: _ bi:: value, boost:: arg<2> () ()>) this) -> 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|note: шаблон 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| примечание: невозможно преобразовать '(& a)->boost::_bi::list2::operator[]((* &((boost::_bi::list3 (*)) (), boost:: _ bi:: value, boost:: arg<2> () ()>) this) -> 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);
Исходный пример терпит неудачу, потому что экземпляр объекта, для которого будет вызываться функция-член, не передается 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));
Ошибка компилятора, опубликованная в ответе Lou, указывает на то, что ioclient
функция-член пытается быть вызвана с дескриптором экземпляра iodata
несовместимый тип. За iodata
чтобы быть совместимым типом, он должен быть унаследован от ioclient
, Если это предполагаемая иерархия типов, проверьте правильность наследования. В противном случае тщательно сопоставьте типы аргументов и позиции с привязываемой функцией.