software para for c++ boost c++11 boost-asio boost-bind

c++ - para - ¿Por qué no se puede usar indistintamente std:: bind and boost:: bind en este tutorial de Boost.Asio?



boost para c++ (4)

Estaba probando los diferentes tutoriales en la documentación de Boost.Asio e intenté reemplazar los componentes boost con los de C ++ 11. Sin embargo, recibí un error al usar std :: bind en Timer.5 - Sincronización de manejadores en programas multiproceso . Aquí está el código propuesto:

#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; }

Intenté reemplazar boost::thread por std::thread y boost::bind por std::bind . Aquí está mi código:

#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(); }

Al compilar con GCC 4.7, recibí este error en tiempo de compilación:

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&& ...)

¿De dónde viene este error, teniendo en cuenta que no usé ningún boost::asio::placeholders (como se explica en esta pregunta de stackoverflow si debería std :: bind ser compatible con boost :: asio? )?


Como ya está usando C ++ 11: lambdas puede ser una alternativa a std :: bind para usted, por ejemplo, std :: thread t (& io {io.run ();}) ;. Esto evita por completo la resolución de sobrecarga.

Para obtener la salida correcta, la solución (en asio standalone o boost :: asio) es:

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();});

Consulte "Eficacia moderna de C ++" en "Elemento 31 Evitar los modos de captura predeterminados".


Este fue un gran PITA para averiguar, así que gracias a Dietmar por la pista. para aquellos que usan boost :: bind, su solución se ve así:

// 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;


La función miembro boost::asio::io_service::run() está sobrecargada: una versión no toma argumentos mientras que otra versión toma un argumento. Es decir, tomar la dirección de of boost::asio::io_service::run requiere un contexto en el que el compilador pueda deducir directamente la firma de la función. Sin embargo, no se requiere que std::bind() haga magia de deducción mientras parece que boost::bind() intenta localizar una sobrecarga coincidente, es decir, parece que su primer tipo de argumento se restringe fácilmente (asumiendo que el ejemplo de boost sí compila).

Para solucionar este problema, puede especificar explícitamente el tipo del primer argumento para std::bind() (también debería funcionar con boost::bind() ), por ejemplo, de esta forma:

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

No he comprobado si el estándar hace algún requisito, pero si de hecho no lo hace, consideraría una implementación que no es heroica para deducir que el tipo de argumento es de mejor calidad, aunque funciona menos: requiere que el usuario escribe código que puede compilar sin cambios en otro compilador.


Solo una nota rápida, en C ++ 11 en adelante puedes usar lambdas para evitar todos los problemas y simplificar todo el asunto. El viejo:

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

o la versión std ::

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

convertirse en justo:

std::thread t([&io_service](){io_service.run();});