ゲームのコードを書いてたら std::remove_if を使ったところでコンパイルエラーが出たので、備忘録としてまとめておく!
発生したエラー
とりあえずエラーメッセージはこんな感じ。
error C3493: 既定のキャプチャ モードが指定されていないため、'this' を暗黙的にキャプチャできません
error C2327: 'EnemyBullets::m_pEnemy': 型名、スタティック、または列挙子ではありません。
error C2065: 'm_pEnemy': 定義されていない識別子です。
いやいや、なんで m_pEnemy が未定義って言われるの!?🤔
ちゃんとクラスのメンバ変数として定義してるのに…
問題のコード
エラーが出たコードはこんな感じ。
m_bullets.erase(std::remove_if(m_bullets.begin(), m_bullets.end(),
[](const std::unique_ptr<EnemyBullet>& bullet) {
return bullet->IsExpired() ||
(bullet->GetBulletPosition().y < 0.0f && bullet->GetBulletType() != EnemyBullet::BulletType::VERTICAL) ||
m_pEnemy->GetPlayerHitByEnemyBullet(); // ここでエラー発生
}),
m_bullets.end());
弾が画面外に出たときや、プレイヤーに当たったときに削除する処理なんだけど、
m_pEnemy が見つからないって言われる。
原因:ラムダ式のキャプチャリストに this がない!
C++のラムダ式では、外部の変数を使うときにキャプチャしないとダメ。
今回 m_pEnemy は EnemyBullets クラスのメンバ変数だから、
ラムダの外側にある this をキャプチャしないとアクセスできない。
キャプチャリストとは?
ラムダ式の [] の中に何を入れるかで、外部変数をどう扱うか決まる。
キャプチャ | 説明 |
---|---|
[] | 何もキャプチャしない(今回のエラー原因) |
[=] | すべての外部変数を値渡しでキャプチャ |
[&] | すべての外部変数を参照渡しでキャプチャ |
[this] | this ポインタをキャプチャ(今回の解決策) |
[m_pEnemy] | m_pEnemy だけをコピーキャプチャ |
解決策:this をキャプチャする!
this をキャプチャすればOK!
修正後のコードがこちら👇
m_bullets.erase(std::remove_if(m_bullets.begin(), m_bullets.end(),
[this](const std::unique_ptr<EnemyBullet>& bullet) { // `this` をキャプチャ
return bullet->IsExpired() ||
(bullet->GetBulletPosition().y < 0.0f && bullet->GetBulletType() != EnemyBullet::BulletType::VERTICAL) ||
this->m_pEnemy->GetPlayerHitByEnemyBullet(); // `this->` をつけると明示的になる
}),
m_bullets.end());
これでコンパイルが通るようになった!🎉
まとめ
ラムダ式の中でクラスのメンバ変数を使うときは this をキャプチャしないとエラーになる!
キャプチャリスト [] を [this] にするだけで解決!
this-> をつけると、より明示的にメンバ変数を使ってるのがわかる!
C++のラムダって便利だけど、キャプチャの仕組みをちゃんと理解してないとハマるな〜💦
また同じエラーで悩まないように、備忘録として残しておく!🚀