2012-01-28 11 views
16

Estaba probando los diferentes tutoriales en la documentación de Boost.Asio y traté de reemplazar los componentes de boost con los de C++ 11. Sin embargo, recibí un error al usar std :: bind en Timer.5 - Synchronising handlers in multithreaded programs. Aquí está el código propuesto:¿Por qué no se pueden usar std :: bind y boost :: bind intercambiablemente en este tutorial de Boost.Asio?

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

Traté de sustituir 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, tengo este error de 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&& ...) 

Dónde está llegando este error, teniendo en cuenta que yo no usar cualquier boost::asio::placeholders (como se explica en esta pregunta stackoverflow Should std::bind be compatible with boost::asio?)?

+0

Posible duplicado: consulte http://stackoverflow.com/questions/8924149/should-stdbind-be-compatible-with-boostasio). – mark

+6

Dado que ya está usando C++ 11: lambdas puede ser una alternativa para 'std :: bind' para usted, por ejemplo,' std :: thread t ([& io]() {io.run();}); '. Esto evita la resolución de sobrecarga completamente. – mavam

Respuesta

34

La función de miembro boost::asio::io_service::run() está sobrecargada: una versión no toma ningún argumento, mientras que otra versión toma un argumento. Es decir, tomar la dirección de boost::asio::io_service::run requiere un contexto en el cual el compilador puede deducir directamente la firma de la función. Sin embargo, std::bind() no es necesario para hacer magia de deducción, mientras que parece que boost::bind() intenta localizar una sobrecarga coincidente, es decir, parece que su primer tipo de argumento se restringe fácilmente (suponiendo que el ejemplo de impulso compila realmente).

En este problema, puede especificar explícitamente el tipo del primer argumento en std::bind() (también debería funcionar con boost::bind()) p. de esta manera:

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

No he comprobado si la norma hace que cualquier requisito, pero si de hecho no hace ningún requisito que yo consideraría una aplicación que Sí no ir a heroicidades para deducir el tipo de argumento a ser de mejor calidad aunque hace menos trabajo: requiere que el usuario escriba el código que puede compilar sin modificaciones en otro compilador.

1

Este fue un gran PITA para averiguar, así que gracias Dietmar por la pista. para aquellos que utilizan el impulso :: vinculación, la 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; 
11

Sólo una pequeña nota, en C++ 11 en adelante sólo se puede utilizar lambdas de evitar todos los faff y simplificar todo esto en gran medida. La antigua:

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

o el std :: Versión:

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

se convierten simplemente:

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

¡mucho mejor! – UmNyobe

0

Since you're already using C++11: lambdas may be an alternative to std::bind for you, e.g., std::thread t(&io { io.run(); });. This avoid the overload resolution entirely.

para obtener la salida correcta, la solución (en autónomo asio 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();}); 

Ver "eficaz Moderno C++" en el "Punto 31 Evita los modos de captura por defecto."

Cuestiones relacionadas