[解決済み] ラムダでの移動キャプチャ
質問
C++11のラムダでmove(rvalue referenceともいう)を捕捉するにはどうすればよいですか?
このようなことを書こうとしています。
std::unique_ptr<int> myPointer(new int);
std::function<void(void)> example = [std::move(myPointer)]{
*myPointer = 4;
};
解決方法は?
C++14の一般化ラムダキャプチャ
C++14では、いわゆる 一般化ラムダキャプチャ . これにより、移動捕捉が可能になります。以下は、C++14で合法なコードになります。
using namespace std;
// a unique_ptr is move-only
auto u = make_unique<some_type>( some, parameters );
// move the unique_ptr into the lambda
go.run( [ u = move(u) ] { do_something_with( u ); } );
しかし、キャプチャーした変数は、そうやって何でも初期化できるという意味では、もっと一般的なものです。
auto lambda = [value = 0] mutable { return ++value; };
C++11では、これはまだ可能ではありませんが、ヘルパー型に関わるいくつかのトリックがあります。幸いなことに、Clang 3.4コンパイラはすでにこの素晴らしい機能を実装しています。このコンパイラは2013年12月か2014年1月にリリースされる予定ですが、その場合は 最近のリリースペース を維持する予定です。
UPDATE は Clang 3.4コンパイラ は、当該機能を搭載して2014年1月6日にリリースされました。
ムーブキャプチャーの回避策
以下は、ヘルパー関数の実装です。
make_rref
人工的な手の捕獲を支援する
#include <cassert>
#include <memory>
#include <utility>
template <typename T>
struct rref_impl
{
rref_impl() = delete;
rref_impl( T && x ) : x{std::move(x)} {}
rref_impl( rref_impl & other )
: x{std::move(other.x)}, isCopied{true}
{
assert( other.isCopied == false );
}
rref_impl( rref_impl && other )
: x{std::move(other.x)}, isCopied{std::move(other.isCopied)}
{
}
rref_impl & operator=( rref_impl other ) = delete;
T && move()
{
return std::move(x);
}
private:
T x;
bool isCopied = false;
};
template<typename T> rref_impl<T> make_rref( T && x )
{
return rref_impl<T>{ std::move(x) };
}
そして、この関数のテストケースは、私の gcc 4.7.3 で正常に実行されました。
int main()
{
std::unique_ptr<int> p{new int(0)};
auto rref = make_rref( std::move(p) );
auto lambda =
[rref]() mutable -> std::unique_ptr<int> { return rref.move(); };
assert( lambda() );
assert( !lambda() );
}
ここでの欠点は
lambda
はコピー可能であり、コピーした際に
rref_impl
が失敗し、実行時バグが発生します。以下の方法は、コンパイラがエラーを検出するため、より良い、さらに汎用的な解決策になるかもしれません。
C++11で一般化されたラムダキャプチャをエミュレートする
もう一つ、一般化されたラムダ・キャプチャーを実装する方法について考えてみましょう。関数
capture()
(その実装はさらに下にあります)は次のようになります。
#include <cassert>
#include <memory>
int main()
{
std::unique_ptr<int> p{new int(0)};
auto lambda = capture( std::move(p),
[]( std::unique_ptr<int> & p ) { return std::move(p); } );
assert( lambda() );
assert( !lambda() );
}
ここで
lambda
はファンクタオブジェクト(ほぼ本物のラムダ)であり、このオブジェクトは
std::move(p)
に渡されるため
capture()
. の第2引数は
capture
は,キャプチャした変数を引数にとるラムダである.このとき
lambda
が関数オブジェクトとして使われた場合、渡されたすべての引数はキャプチャされた変数の後に引数として内部のラムダに転送されます。(この例では、それ以上転送される引数はありません)。基本的には、前の解答と同じことが起こります。以下は
capture
が実装されています。
#include <utility>
template <typename T, typename F>
class capture_impl
{
T x;
F f;
public:
capture_impl( T && x, F && f )
: x{std::forward<T>(x)}, f{std::forward<F>(f)}
{}
template <typename ...Ts> auto operator()( Ts&&...args )
-> decltype(f( x, std::forward<Ts>(args)... ))
{
return f( x, std::forward<Ts>(args)... );
}
template <typename ...Ts> auto operator()( Ts&&...args ) const
-> decltype(f( x, std::forward<Ts>(args)... ))
{
return f( x, std::forward<Ts>(args)... );
}
};
template <typename T, typename F>
capture_impl<T,F> capture( T && x, F && f )
{
return capture_impl<T,F>(
std::forward<T>(x), std::forward<F>(f) );
}
この2番目の解決策は、捕捉された型がコピー可能でない場合、ラムダをコピーすることを無効にするので、よりクリーンである。最初の解決法では、実行時に
assert()
.
関連
-
[解決済み】C++ 非推奨の文字列定数から「char*」への変換について
-
[解決済み] string does not name a type Errorが発生するのはなぜですか?
-
[解決済み] error: 'if' の前に unqualified-id を期待した。
-
[解決済み] ムーブセマンティクスとは何ですか?
-
[解決済み] リスト内包とラムダ+フィルタの比較
-
[解決済み] std::move()とは何ですか?また、どのような場合に使用するのですか?
-
[解決済み] Distinct() with lambda?
-
[解決済み] C++11 rvalues と移動セマンティクスの混乱(return 文)
-
[解決済み】画像処理。コカ・コーラ缶」認識のためのアルゴリズム改良
-
[解決済み】C++11のラムダ式って何?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】C++ - 解放されるポインタが割り当てられていないエラー
-
[解決済み】C-stringを使用すると警告が表示される。"ローカル変数に関連するスタックメモリのアドレスが返される"
-
[解決済み】C++でユーザー入力を待つ【重複あり
-
[解決済み】C++エラーです。"配列は中括弧で囲まれたイニシャライザーで初期化する必要がある"
-
[解決済み】C++でランダムな2倍数を生成する
-
[解決済み】'cout'は型名ではない
-
[解決済み】c++でstd::vectorを返すための効率的な方法
-
[解決済み】Visual C++で "Debug Assertion failed "の原因となる行を見つける。
-
[解決済み] 解決済み] `pthread_create' への未定義の参照 [重複] [重複
-
[解決済み] 変数サイズのオブジェクトが初期化されないことがある c++