2013-02-07 43 views
5

Sử dụng MSVC2012,Tại sao std :: packaged_task <void()> không hợp lệ?

Đoạn mã dưới đây sẽ biên dịch và chạy như mong đợi

std::packaged_task< int() > task([]()->int{ std::cout << "hello world" << std::endl; return 0; }); 
std::thread t(std::move(task)); 
t.join(); 

trong khi đoạn mã sau sẽ thất bại trong việc biên dịch và chạy

std::packaged_task< void() > task([](){ std::cout << "hello world" << std::endl; }); 
std::thread t(std::move(task)); 
t.join(); 

Tại sao điều này như vậy?

Edit: Là một workaround, nó có thể sử dụng std :: hứa sẽ có được một std :: tương lai trên một hàm trả về void

std::promise<void> promise; 
auto future = promise.get_future(); 
std::thread thread([](std::promise<void> &p){ std::cout << "hello world" << std::endl; p.set_value(); }, std::move(promise)); 
future.wait(); 

Lưu ý rằng có một lỗi trong thư viện vs2012 với std :: thread buộc bạn vượt qua lời hứa dưới dạng tham chiếu giá trị l và di chuyển lời hứa, nó sẽ không biên dịch nếu bạn chuyển lời hứa theo giá trị hoặc tham chiếu giá trị r. Điều này được cho là do việc thực hiện sử dụng std :: bind() không hoạt động như mong đợi.

+6

Thú vị ... lỗi thứ hai đưa ra khi biên dịch là gì? – Yuushi

+0

Đây có thể là lỗi trong MSVC++. –

+4

Từ những gì tôi truy tìm vào việc thực hiện , nó cuối cùng đi xuống để lưu trữ trạng thái thực thi đối tượng hàm, cụ thể trong một lớp mẫu được gọi là '_State_manager'. Không có sự chuyên môn hóa của '_State_manager' cho trạng thái' void', giống như một lỗi. Tôi có thể hoàn toàn ra ngoài ăn trưa, nhưng đó là nơi nó xuất hiện mọi thứ sụp đổ. – WhozCraig

Trả lời

5

Đây là lỗi trong MSVC2012. Có khá nhiều lỗi trong việc triển khai thư viện luồng mà gửi cùng với MSVC2012. Tôi đã đăng một phần danh sách trong bài đăng trên blog của tôi so sánh nó với thư viện Just :: Thread của tôi: http://www.justsoftwaresolutions.co.uk/news/just-thread-v1.8.0-released.html

+0

"Với thư viện VS2012, khi std :: async được sử dụng với chính sách khởi chạy của std :: launch :: async, hàm hủy của lệnh trả về std :: instance trong tương lai không đợi cho chuỗi hoàn tất." - Tôi sẽ chọn nó. Các đối số rằng các văn bản tiêu chuẩn có một lỗi trong đó là hấp dẫn. – Yakk

+1

Từ ngữ chuẩn cho 'std :: async' đã được lựa chọn cẩn thận và Microsoft đã quyết định đi ngược lại tiêu chuẩn. Đây không phải là một lỗi trong tiêu chuẩn, mặc dù một số người tin rằng đó là một lựa chọn tồi. –

+0

Điều này thật đáng thất vọng, một số lỗi này sẽ bị bắt gặp bởi các trường hợp thử nghiệm đơn giản nhất. Tôi mong đợi nhiều hơn từ Microsoft. – aCuria

3

này hoạt động trong gcc 4.7.2:

#include <thread> 
#include <future> 
#include <iostream> 

int main() { 
    std::packaged_task< void() > task([](){ std::cout << "hello world" << std::endl; }); 
    std::thread t(std::move(task)); 
    t.join(); 
    std::packaged_task< int() > task2([]()->int{ std::cout << "hello world" << std::endl; return 0; }); 
    std::thread t2(std::move(task2)); 
    t2.join(); 
} 

Cùng với khảo cổ học @WhozCraig 's ngụ ý rằng đây có lẽ là một lỗi trong MSVC2012.

Để giải quyết sự cố, hãy thử sử dụng struct Nothing {}; hoặc nullptr_t làm giá trị trả lại của bạn?

2

Sự cố vẫn còn trong MSVS 2013RC, nhưng tôi đã thực hiện bản vá tạm thời này trong khi MS sửa nó. Nó là một chuyên môn của packaged_task cho void (...), vì vậy tôi đề nghị đặt nó trong một tệp tiêu đề và bao gồm nó sau tiêu đề tiêu chuẩn. Chú ý rằng make_ready_at_thread_exit() không được triển khai và một số hàm chưa được kiểm tra đầy đủ, sử dụng tại rủi ro của riêng bạn.

namespace std { 

template<class... _ArgTypes> 
class packaged_task<void(_ArgTypes...)> 
{ 
    promise<void> _my_promise; 
    function<void(_ArgTypes...)> _my_func; 

public: 
    packaged_task() { 
    } 

    template<class _Fty2> 
    explicit packaged_task(_Fty2&& _Fnarg) 
     : _my_func(_Fnarg) { 
    } 

    packaged_task(packaged_task&& _Other) 
     : _my_promise(move(_Other._my_promise)), 
     _my_func(move(_Other._my_func)) { 
    } 

    packaged_task& operator=(packaged_task&& _Other) { 
     _my_promise = move(_Other._my_promise); 
     _my_func = move(_Other._my_func); 
     return (*this); 
    } 

    packaged_task(const packaged_task&) = delete; 
    packaged_task& operator=(const packaged_task&) = delete; 

    ~packaged_task() { 
    } 

    void swap(packaged_task& _Other) { 
     _my_promise.swap(_Other._my_promise); 
     _my_func.swap(_Other._my_func); 
    } 

    explicit operator bool() const { 
     return _my_func != false; 
    } 

    bool valid() const { 
     return _my_func != false; 
    } 

    future<void> get_future() { 
     return _my_promise.get_future(); 
    } 

    void operator()(_ArgTypes... _Args) { 
     _my_func(forward<_ArgTypes>(_Args)...); 
     _my_promise.set_value(); 
    } 

    void reset() { 
     swap(packaged_task()); 
    } 
}; 

}; // namespace std 
Các vấn đề liên quan