31

への引数として非 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::asyncしかし、 に渡された値をラップすればstd::reference_wrapper、すべて問題ありません。これはstd::async引数を値で受け取るためだと思いますが、エラーの理由はまだわかりません。

4

3 に答える 3

47

これは、意図的な設計の選択/トレードオフです。

asyncまず、渡された functionoid が参照によって引数を取るかどうかを確認することは必ずしも可能ではありません。(単純な関数ではなく関数オブジェクトの場合は、関数呼び出し演算子がオーバーロードされている可能性がありますasync) ."

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

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

しかし、非 const 左辺値参照パラメーターが本当に本当に必要な場合はどうすればよいでしょうか? ダングリング参照と競合状態に注意することを約束したらどうなるでしょうか? それstd::refがそのためです。これは、危険な参照セマンティクスに対する明示的なオプトインです。「私はここで何をしているのか知っている」というあなたの言い方です。

于 2013-08-21T14:48:36.690 に答える
25

std::async(および完全な転送を行うその他の関数) 渡す引数の型を調べて、何をすべきかを判断します。彼らは、その議論が最終的にどのように使用されるかを見ていません。したがって、参照によってオブジェクトを渡すには、std::async参照を使用していることを伝える必要があります。ただし、単に参照を渡すだけではそれはできません。std::ref(value)参照渡しに使用する必要がありvalueます。

于 2013-08-21T14:49:45.720 に答える
15

この問題自体はstd::async()、操作の結果を定義するときに、すべての引数が'edでstd::async()使用されます。は任意の型を取り、それらを転送してある場所に保存するため、これは合理的です。それらを保存するには、関数オブジェクトと引数の値が必要です。したがって、次のように使用されます。std::result_of<...>::typestd::decay<...>::typestd::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
于 2013-08-21T14:54:22.557 に答える