2016-04-07 13 views
0

だから私はスレッド化したいメンバ関数を持つオブジェクトを持っています。この関数はオブジェクトの外にいくつかのリソースを操作することになるので、私はこの関数の引数として参照することによりミューテックスを渡したい:std :: mutexを引数としてメンバー関数をスレッディング

#include <iostream> 
#include <mutex> 
#include <thread> 

class foo 
{ 
    public: 
     void bar(std::mutex &m) 
     { 
      std::lock_guard<std::mutex> lock(m); 
      std::cout << "Threading this function works!" << std::endl; 
     } 
}; 


int main() 
{ 
    foo a; 
    std::mutex m; 
    std::thread bar_thread(&foo::bar, std::ref(a), std::ref(m)); 
    bar_thread.join(); 
    return 0; 
} 

これはコンパイルおよびVisual Studio 2013/VC++で細かい動作します。しかし、これをg ++でコンパイルしようとすると失敗します。エラーメッセージも、それは非常に困難コンパイラが文句を言っているかを理解することができますこれは非常に不可解です:

/usr/include/c++/4.8/functional: In instantiation of ‘struct std::_Bind_simple<std::_Mem_fn<void (foo::*)(std::mutex&)>(std::reference_wrapper<foo>, std::reference_wrapper<std::mutex>)>’: 
/usr/include/c++/4.8/thread:137:47: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (foo::*)(std::mutex&); _Args = {std::reference_wrapper<foo>, std::reference_wrapper<std::mutex>}]’ 
thread_test.cpp:63:69: required from here 
/usr/include/c++/4.8/functional:1697:61: error: no type named ‘type’ in ‘class std::result_of<std::_Mem_fn<void (foo::*)(std::mutex&)>(std::reference_wrapper<foo>, std::reference_wrapper<std::mutex>)>’ 
     typedef typename result_of<_Callable(_Args...)>::type result_type; 
                  ^
/usr/include/c++/4.8/functional:1727:9: error: no type named ‘type’ in ‘class std::result_of<std::_Mem_fn<void (foo::*)(std::mutex&)>(std::reference_wrapper<foo>, std::reference_wrapper<std::mutex>)>’ 
     _M_invoke(_Index_tuple<_Indices...>) 
     ^

私はそれはおそらく、STDの非コピー可否::ミューテックスととは何かを持っている疑いを持っていますg ++のstd :: refの実装は、vC++のものとは異なりますか?しかしこれは単なるランダムな推測です。

2つの異なるC++コンパイラの微妙な知識に精通している人なら、この問題の原因と解決方法を知っていますか?

オブジェクトへのポインタではなく、基準(ラッパー)から渡されたときは、この++ Gにコンパイル
+1

gccのバージョン? –

+0

@RichardHodges g ++ 4.8.4 –

答えて

1

INVOKEの 'this'引数としてreference_wrapperを渡します。ここで、fはメンバー関数ポインタで、C++ 17の標準になります。

それまでは、厳密には有効ではありません。

代替:

#include <mutex> 

#include <thread> 
#include <iostream> 

class foo 
{ 
    public: 
     void bar(std::mutex &m) 
     { 
      std::lock_guard<std::mutex> lock(m); 
      std::cout << "Threading this function works!" << std::endl; 
     } 
}; 


int main() 
{ 
    foo a; 
    std::mutex m; 
    std::thread bar_thread(&foo::bar, std::addressof(a), std::ref(m)); 
    bar_thread.join(); 
    return 0; 
} 

推論:

std::thread::thread<>(f, args...)はINVOKEの面に実装されている(F、引数...)

ここにいくつかの基準物質:

http://en.cppreference.com/w/cpp/concept/Callable

+0

これは動作するようですが、ありがとう! –

+1

@ Fat-chunk標準で動作することが保証されています! –

+0

もう1つ、関数がmutexを引数として取っていないときに、std :: ref()がどのように動作するのでしょうか?または、関数が引数を取る場合にのみ、INVOKEに関して実装されていますか? –

0

:リチャードホッジスによって答えとして、

std::thread bar_thread(&foo::bar, &a, std::ref(m)); 

明らかに、参照ラッパーはCまで呼び出し先としてサポートされていない++ 17。

+0

-std = C++で動作しない限り、バグではありません17 –

+0

@RichardHodges私は標準のその部分に慣れていませんが、私はあなたとcppreferenceの言葉を取っています。 – user2079303

+1

私はそれが何よりも歴史の事故だと思う。想像上のINVOKE関数のarg2である参照ラッパーは、これまでの標準では言及されていませんでした(おそらく誰も必要と思わないから)。 std :: invoke()は、C++ 17の関数として存在します。その結果、顔を上げることができました。 –

関連する問題