2012-01-28 15 views
16

Tôi đã thử các hướng dẫn differents trong tài liệu Boost.Asio và cố gắng thay thế các thành phần tăng với C++ 11. Tuy nhiên, tôi gặp lỗi khi sử dụng std :: bind trong Timer.5 - Synchronising handlers in multithreaded programs. Đây là mã đề xuất:Tại sao không thể std :: ràng buộc và tăng :: ràng buộc được sử dụng thay thế cho nhau trong hướng dẫn này 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; 
} 

tôi đã cố gắng để thay thế boost::thread bởi std::threadboost::bind bởi std::bind. Đây là mã của tôi:

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

Khi biên dịch với GCC 4.7, tôi nhận này lỗi thời gian biên dịch:

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

đâu lỗi này đến từ, có tính đến mà tôi đã không sử dụng bất kỳ boost::asio::placeholders (như giải thích trong câu hỏi stackoverflow này Should std::bind be compatible with boost::asio?)?

+0

Có thể trùng lặp: xem http://stackoverflow.com/questions/8924149/should-stdbind-be-compatible-with-boostasio). – mark

+6

Vì bạn đã sử dụng C++ 11: lambdas có thể là giải pháp thay thế để 'std :: bind' cho bạn, ví dụ,' std :: thread t ([& io]() {io.run();}); '. Điều này tránh hoàn toàn quá tải độ phân giải – mavam

Trả lời

34

Chức năng thành viên boost::asio::io_service::run() bị quá tải: một phiên bản không có đối số trong khi phiên bản khác có một đối số. Nghĩa là, lấy địa chỉ của số boost::asio::io_service::run yêu cầu một ngữ cảnh trong đó trình biên dịch có thể trực tiếp suy ra chữ ký của hàm. Tuy nhiên, std::bind() không bắt buộc phải thực hiện phép trừ trừ khi có vẻ như boost::bind() tìm cách xác định quá tải phù hợp tức là dường như loại đối số đầu tiên của nó bị ràng buộc dễ dàng (giả sử ví dụ tăng cường thực sự biên dịch).

Vấn đề xung quanh vấn đề này, bạn có thể chỉ định rõ loại đối số đầu tiên cho std::bind() (nó cũng phải hoạt động với boost::bind()) ví dụ: như thế này:

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

tôi đã không kiểm tra xem tiêu chuẩn làm cho bất kỳ yêu cầu nhưng nếu nó thực sự không làm bất cứ yêu cầu tôi sẽ xem xét một thực hiện mà không không đi đến anh hùng để suy luận kiểu lập luận để có chất lượng tốt hơn mặc dù nó ít hoạt động hơn: nó yêu cầu người dùng viết mã có thể biên dịch không thay đổi trên trình biên dịch khác.

1

Đây là một PITA lớn để tìm ra, vì vậy cảm ơn bạn Dietmar cho gợi ý. đối với những người sử dụng tăng :: ràng buộc, bạn giải pháp trông như thế này:

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

Chỉ cần ghi chú nhanh, trong C++ lambdas 11 trở đi bạn chỉ có thể sử dụng để tránh tất cả các faff và đơn giản hóa toàn bộ điều đáng kể. Cũ:

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

hoặc std :: phiên bản:

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

trở thành chỉ:

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

tốt hơn rất nhiều! – 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.

Để có được kết quả đúng, các giải pháp (trong độc lập ASIO hoặc tăng :: asio) là:

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

Xem "Hiệu quả hiện đại C++" trong "Mục 31 Tránh chế độ chụp mặc định."