5

以下は、ローカル変数をクロージャーにバインドする最も安価な方法であると思います。

void ByRValueReference(A&& a) {
}

std::function<void ()> CreateClosureByRValueReference() {
  A a;
  std::function<void ()> f = std::bind(&ByRValueReference, std::move(a)); // !!!
  return f;
}

ただし、Clang 3.1 ではコンパイルできません。

error: no viable conversion from '__bind<void (*)(A &&), A>' to 'std::function<void ()>'

および gcc 4.6.1:

/usr/include/c++/4.6/functional:1778:2: error: no match for call to ‘(std::_Bind<void (*(A))(A&&)>) ()’

標準に違反していますか、それとも標準ライブラリが壊れているだけですか?

4

1 に答える 1

3

これは の設計によるものですstd::bind。完全な仕様は 20.8.9.1.2 関数テンプレート バインド [func.bind.bind] にありますが、この場合はパラグラフ 10 の最後の箇条書き (バインドされたパラメーターがどのように使用されるかを説明しています) が適用されます。

— それ以外の場合、値はtidであり、そのタイプViTiD cv &

つまり、(move 構築から) をstd::move(a)格納する呼び出しラッパーが生成され、 が使用されると、このメンバーは左辺値として転送されます(呼び出しラッパーの cv 修飾子と一致する追加の cv 修飾子を使用しますが、私は余談)。右辺値として渡されたにもかかわらず。Aoperator()

この種の不一致は、ラムダを介して解決できます。

std::bind([](A& a) { ByRValueReference(std::move(a)); }, std::move(a))

これは、ラップされた結果の呼び出しへのさらなる呼び出しが疑わしいことはより明白であると主張できます (Aメンバーが移動された可能性があるため) がstd::bind、全体としての動作があまり好きではありません。

于 2012-04-07T11:38:16.980 に答える