this questionで作業している間に、GCC(v4.7)の実装であるstd::function
が値をとると引数を移動することに気付きました。次のコードは、この動作を示しています。`std :: function`は引数を移動できますか?
#include <functional>
#include <iostream>
struct CopyableMovable
{
CopyableMovable() { std::cout << "default" << '\n'; }
CopyableMovable(CopyableMovable const &) { std::cout << "copy" << '\n'; }
CopyableMovable(CopyableMovable &&) { std::cout << "move" << '\n'; }
};
void foo(CopyableMovable cm)
{ }
int main()
{
typedef std::function<void(CopyableMovable)> byValue;
byValue fooByValue = foo;
CopyableMovable cm;
fooByValue(cm);
}
// outputs: default copy move move
私たちはここを参照してくださいcm
のコピーが行われていること(byValue
のパラメータは値によって取られているので、合理的なようだ)が、その後2つの動きがあります。 function
はcm
のコピーで動作しているため、引数を移動するという事実は重要でない実装の詳細と見ることができます。しかし、この動作は、いくつかのトラブルwhen using function
together with bind
原因:
#include <functional>
#include <iostream>
struct MoveTracker
{
bool hasBeenMovedFrom;
MoveTracker()
: hasBeenMovedFrom(false)
{}
MoveTracker(MoveTracker const &)
: hasBeenMovedFrom(false)
{}
MoveTracker(MoveTracker && other)
: hasBeenMovedFrom(false)
{
if (other.hasBeenMovedFrom)
{
std::cout << "already moved!" << '\n';
}
else
{
other.hasBeenMovedFrom = true;
}
}
};
void foo(MoveTracker, MoveTracker) {}
int main()
{
using namespace std::placeholders;
std::function<void(MoveTracker)> func = std::bind(foo, _1, _1);
MoveTracker obj;
func(obj); // prints "already moved!"
}
標準によって許可され、この動作はありますか? std::function
は引数を移動できますか?その場合、bind
によって返されたラッパーを、複数のプレースホルダを処理する際に予期しない動作を引き起こすにもかかわらず、by-valueパラメータを使用してstd::function
に変換できますか?
問題は、 'std :: function'よりもプレースホルダが多いようです。つまり、「結び」を作成するときに、元の引数から両方の期待される出力に移動が使用されるという事実。 –
興味深いことに、Visual C++ 11コンパイラは、最初の例で "default copy move"を出力し、 "already moved!" 2番目にこの追加の動きがstd :: functionの機能や完全なフォワーディングの内部動作から来るのではないかと思います。 @MatthieuM。 –
。あなたは詳しく説明できますか?プレースホルダの実装にはあまり慣れていません。問題がプレースホルダから来た場合、 'std :: function'を使用する代わりに、' auto'を使用して "bind-wrapper"型を推測するときに、どのように問題が発生しないのでしょうか? –