Почему нельзя использовать std :: bind и boost :: bind взаимозаменяемо в этих уроках Boost.Asio - PullRequest
16 голосов
/ 28 января 2012

Я пробовал различные руководства в документации Boost.Asio и пытался заменить компоненты boost на C ++ 11. Тем не менее, я получил ошибку при использовании std :: bind в Timer.5 - Синхронизация обработчиков в многопоточных программах . Вот код, предложенный:

#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

class printer { /* Not relevent here */ };

int main()
{
  boost::asio::io_service io;
  printer p(io);
  boost::thread t(boost::bind(&boost::asio::io_service::run, &io));
  io.run();
  t.join();

  return 0;
}

Я пытался заменить boost::thread на std::thread и boost::bind на std::bind. Вот мой код:

#include <functional>
#include <iostream>
#include <thread>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

class printer { /* Not relevent here */ };

int main() {
    boost::asio::io_service io;
    printer p(io);
    std::thread t(std::bind(&boost::asio::io_service::run, &io));
    io.run();
    t.join();
}

При компиляции с GCC 4.7 я получил эту ошибку времени компиляции:

g++ -std=c++0x main.cpp -lboost_system -lboost_date_time -lpthread
main.cpp: In function ‘int main()’:
main.cpp:52:60: erreur: no matching function for call to ‘bind(<unresolved overloaded function type>, boost::asio::io_service*)’
main.cpp:52:60: note: candidates are:
/usr/include/c++/4.6/functional:1444:5: note: template<class _Functor, class ... _ArgTypes> typename std::_Bind_helper::type std::bind(_Functor&&, _ArgTypes&& ...)
/usr/include/c++/4.6/functional:1471:5: note: template<class _Result, class _Functor, class ... _ArgTypes> typename std::_Bindres_helper::type std::bind(_Functor&&, _ArgTypes&& ...)

Откуда происходит эта ошибка, учитывая, что я не использовал никаких boost::asio::placeholders (как объясняется в этом вопросе stackoverflow Должен ли std :: bind быть совместим с boost :: asio? )?

Ответы [ 4 ]

35 голосов
/ 29 января 2012

Функция-член boost::asio::io_service::run() перегружена: одна версия не принимает аргументов, а другая версия принимает один аргумент.То есть получение адреса boost::asio::io_service::run требует контекста, в котором компилятор может напрямую определить сигнатуру функции.Тем не менее, std::bind() не требуется делать магию дедукции, в то время как кажется, что boost::bind() пытается найти совпадающую перегрузку, т.е. кажется, что его первый тип аргумента легко ограничен (при условии, что пример boost действительно компилируется).

Чтобы обойти эту проблему, вы можете явно указать тип первого аргумента для std::bind() (он также должен работать с boost::bind()), например, так:

std::bind(static_cast<size_t (boost::asio::io_service::*)()>(&boost::asio::io_service::run), &io);

У меня нетпроверил, предъявляет ли стандарт какие-либо требования, но если он действительно не отвечает каким-либо требованиям, я бы рассмотрел реализацию, которая не идет к героизму, чтобы сделать тип аргумента более качественным, хотя он выполняет меньше работы:это требует, чтобы пользователь написал код, который может компилироваться без изменений на другом компиляторе.

12 голосов
/ 12 ноября 2014

Просто краткое замечание, в C ++ 11 и далее вы можете просто использовать лямбда-выражения, чтобы избежать всех ошибок и значительно упростить все это.Старый:

boost::thread t(boost::bind(&boost::asio::io_service::run, &io));

или std :: версия:

std::thread t(boost::bind(static_cast<size_t (boost::asio::io_service::*)()>(&boost::asio::io_service::run), &io_service));

становятся просто:

std::thread t([&io_service](){io_service.run();});
1 голос
/ 02 января 2013

Это была огромная PITA, которую нужно выяснить, так что спасибо Dietmar за подсказку. для тех, кто использует boost :: bind, ваше решение выглядит так:

// create the io_service    

boost::asio::io_service io_service;

 // assign some work to asio before starting
 {
    io_service.post(&some_work);   // just for example
    ....
 }

boost::thread t(boost::bind(static_cast<size_t (boost::asio::io_service::*)()>(&boost::asio::io_service::run), &io_service));

// work should be executed in a new thread

t.join()

return;
0 голосов
/ 26 июня 2016

Поскольку вы уже используете C ++ 11: лямбды могут быть для вас альтернативой std :: bind, например, std :: thread t (& io {io.run ();}) ;. Это полностью исключает разрешение перегрузки.

Чтобы получить правильный вывод, решение (в asio standalone или boost :: asio):

asio::io_service io;
auto ptrToIoService = &io;
printer p(io);

//asio::thread t(std::bind(&asio::io_service::run, &io));
//asio::thread t([&io]() {io.run();});
asio::thread t([ptrToIoService] () { ptrToIoService->run();});

См. «Эффективный современный C ++» в разделе «Элемент 31. Избегайте режимов захвата по умолчанию».

...