2013-08-21 5 views
14

std::asyncに引数として非const参照を渡すことは不可能であることに気付きました。参照によってstd :: asyncに引数を渡すことができません

#include <functional> 
#include <future> 

void foo(int& value) {} 

int main() { 
    int value = 23; 
    std::async(foo, value); 
} 

私のコンパイラ(GCC 4.8.1)は、この例について、次のエラーを与える:

error: no type named ‘type’ in ‘class std::result_of<void (*(int))(int&)>’ 

しかし、私はstd::reference_wrapperstd::asyncに渡された値をラップした場合、すべてがOKです。これは、std::asyncが値で引数を取るためだと思いますが、エラーの理由はまだ分かりません。

+3

'std :: reference_wrapper'をタイプする必要はありません。 'std :: ref'を使います。 – chris

+0

私は 'std :: ref'を使用しますが、ヒントのためにありがとう:) – lizarisk

+0

このエラーの理由に興味があるなら、libstdC++のソースコードを掘り下げなければなりません:http://gcc.gnu .org/onlinedocs/gcc-4.8.1/libstdC++/api/a01256_source.html見るべき行番号はエラーです。がんばろう。 – jrok

答えて

24

これは意図的なデザインの選択/トレードオフです。

まず、asyncに渡された機能停止が、その引数を参照するかどうかを調べることは必ずしも可能ではありません。 (単純な関数ではなく、関数オブジェクトであれば、関数呼び出し演算子がオーバーロードされるなど)。asyncは、「ちょっと、目標関数が何を望んでいるかを確認してみましょう。物事。 "

設計上の問題は、すべての引数を可能であれば参照する(つまり、値が左辺の場合)か、常にコピーを作成するかどうかです。コピーはの安全の選択です:コピーが絡んでくることはありません。コピーは競合状態にならない(本当に変わっていない限り)。それが行われた選択です:すべての引数はデフォルトでコピーされます。

しかし、実際には引数を非const値の参照パラメータに渡すことができないようにメカニズムが記述されています。それは安全のための別の選択肢です。そうしないと、元の左辺値を変更すると予想される関数がコピーを変更し、追跡が非常に難しいバグが発生します。

しかし、実際には非const左辺参照パラメータが必要な場合はどうすればよいですか?あなたが参照や競合条件が絡んでいることに気を付けることを約束すればどうなりますか?それがstd :: refのためのものです。これは、危険な参照セマンティクスへの明示的なオプトインです。それはあなたの言葉です。「私はここで何をしているのか知っています。

15

std::async(そして完璧な転送機能を持つ他の機能)は、何をすべきかを把握するために渡す引数のタイプを見てください。彼らは、その議論がどのように最終的に使用されるかを見ない。したがって、オブジェクトを参照渡しするには、参照を使用していることをstd::asyncに伝える必要があります。しかし、単に参照を渡すことはできません。参考にしてvalueを渡すには、std::ref(value)を使用する必要があります。

+0

非常に明確な答え。 – Sheen

14

問題自体はstd::async()にわずかに関連している:操作の結果を定義する場合、std::async()は、すべての引数がstd::decay<...>::type「EDであることとstd::result_of<...>::typeを使用しています。 std::async()は任意の型を取り、それらをある場所に格納するために転送するため、これは合理的です。それらを格納するには、関数オブジェクトと引数の値が必要です。したがって、std::result_of<...>は次のように使用されます。

typedef std::result_of<void (*(int))(int&)>::type result_type; 

...とintは(intは左辺値型がint&にバインドする必要があるたではありません)int&にバインドすることができないので、これは失敗しました。この場合の失敗は、std::result_of<...>がネストされたtypeを定義していないことを意味します。

次のような質問があります。std::result_of<...>をインスタンス化するために使用したこのタイプは何ですか?考え方は、ResultType(ArgumentTypes...)からなる関数呼び出し構文が濫用されていることです。結果型の代わりに関数型が渡され、std::result_of<...>は、指定された引数リストを使用してその関数型が呼び出されたときに呼び出される関数の型を決定します。関数ポインタ型については、それほど興味深いわけではありませんが、関数型は、オーバーロードを考慮する必要がある関数オブジェクトでもあります。基本的にstd::result_of<...>は次のように使用されます:

typedef void (*function_type)(int&); 
typedef std::result_of<function_type(int)>::type result_type; // fails 
typedef std::result_of<function_type(std::reference_wrapper<int>)>::type result_type; //OK 
+1

+1 IMHOこの投稿はOPに表示されるエラーメッセージを実際に解読するものです。 –

関連する問題