この質問に取り組んでいる間、GCC(v4.7)の実装は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
ここでは、のコピーが実行されていることがわかります( 'sパラメータは値によって取得されるcm
ため、これは妥当と思われます)が、2つの動きがあります。byValue
はのfunction
コピーを操作しているcm
ため、引数を移動するという事実は、重要でない実装の詳細と見なすことができます。ただし、この動作は、 :と一緒に使用function
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
変換できるのは正常ですか?std::function