2013-02-07 11 views
5

なぜstd :: packaged_task <void()>は無効ですか? MSVC2012を使用

次のコードをコンパイルして、なぜこれがそうである

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

実行に失敗しながら、次のコードはコンパイルして

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

を期待通りに実行されますか?

編集:回避策として 、vs2012ライブラリにバグがあることが、ボイド

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

注意を返す関数にはstdを取得することを約束::のstd ::未来を使用することが可能です約束事をl-値参照として渡し、約束を移すことを強いるstd :: threadでは、約束を値渡しまたはr値参照によって渡すとコンパイルされません。これは、実装が期待どおりに動作しないstd :: bind()を使用するためです。

+6

興味深いことに...コンパイル時に2番目のエラーはありますか? – Yuushi

+0

これはおそらくMSVC++のバグです。 –

+4

私はの実装にたどり着き、最終的には関数オブジェクトの実行状態の格納に、特に '_State_manager'というテンプレートクラスで行われます。 '_State_manager'の' void'状態のための特殊化はありません。これはバグかもしれません。私は完全に昼食に出ることもできますが、すべてが崩れているように見えるものです。 – WhozCraig

答えて

5

これはMSVC2012のバグです。 MSVC2012に付属しているスレッドライブラリの実装には、かなりのバグがあります。私は、商業だけで::スレッド・ライブラリと比較すること、私のブログの記事に一部のリストを掲載:http://www.justsoftwaresolutions.co.uk/news/just-thread-v1.8.0-released.html

+0

"VS2012ライブラリでは、std :: asyncの起動ポリシーでstd :: launch :: asyncを使用すると、返されたstd :: futureインスタンスのデストラクタはスレッドの完了を待機しません。 - 私はそれをオプションにします。標準テキストにバグがあるという議論は魅力的です。 – Yakk

+1

'std :: async'の標準的な言葉遣いが慎重に選択され、Microsoftは意図的に標準に反することを決めました。これは標準のバグではありませんが、悪い選択だと信じている人もいます。 –

+0

これは残念ですが、これらのバグの中には、最も簡単なテストケースで捕らえられたものがあります。私はMicrosoftからさらに多くのことを期待していた – aCuria

3

これは、GCC 4.7.2で動作します:一緒に@WhozCraigの考古学と

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

が、これはおそらくMSVC2012のバグであることを意味します。

回避策として、戻り値としてstruct Nothing {};またはnullptr_tを使用してみてください。

2

問題はMSVS 2013RCにそこにまだあるが、MSはそれを修正しながら、私はこの一時的なパッチを作りました。これはvoid(...)のためのpackaged_taskの特殊化です。ヘッダーファイルに入れ、標準ヘッダーの後にインクルードすることをお勧めします。make_ready_at_thread_exit()は実装されておらず、一部の関数は完全にテストされていません。あなた自身のリスク。

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 
関連する問題