0

このゲームには Game クラスがあります。これはシングルトンです...ヘッダー ファイルは次のとおりです。

#ifndef SOKOBAN_GAME_H
#define SOKOBAN_GAME_H
#include <memory>
#include <SDL/SDL.h>
namespace sokoban
{
  class Game
  {
  public:
    static Game* getInstance();
    void startGame();
  private:
    Game();
    ~Game();
    Game(const Game&) = delete;
    Game(Game&&) = delete;
    Game& operator=(const Game&) = delete;
    Game& operator=(Game&&) = delete;

    static std::shared_ptr<Game> instance_;
    SDL_Surface* mainSurface_;
  };
};
#endif

これで、getInstance 関数を除いて、ほとんどの実装ファイルは重要ではなくなりました。

Game* Game::getInstance()
{
  if(!Game::instance_)
  {
    Game::instance_ = std::shared_ptr<Game>(new Game,
    [](Game* ptr)
    {
      delete ptr;
    });
  }

  return Game::instance_.get();
}

ご覧のとおり、私の遅延初期化スタイルではスマート ポインターを使用する必要がありますが、パブリック デストラクタを回避しようとしているため、ラムダをデリータとして使用する必要があります。このコードは正常にコンパイルされますが、コンパイルできません。標準では個別の一意のオブジェクトであると言われているラムダが、特に SO に関するいくつかの質問を見た後、このプライベート メソッドを呼び出すことができる理由のパターンを見つけたようです。

基本的に知りたいのは、例のようなメンバー関数のラムダのアクセス規則です...

4

1 に答える 1

3

規格は5.1.2/3で述べています

ラムダ式の型[...]は一意の[...]クラス型です—クロージャ型と呼ばれます[...]クロージャ型は、最小のブロックスコープ、クラススコープ、または名前空間スコープで宣言されます。対応するラムダ式が含まれています。

これは、(メンバー)関数内で発生するラムダがローカルクラスのように扱われ、周囲の関数のブロックスコープで宣言されることを意味します。ローカルクラスについては、標準では9.8/1で次のように述べています。

[...]ローカルクラスは囲んでいるスコープのスコープ内にあり、囲んでいる関数と同じように関数の外部の名前にアクセスできます。[...]

したがって、ラムダは包含メンバー関数と同じアクセス権を持ちます。つまり、ラムダはクラスのプライベートメンバーにアクセスできます。

ラムダがクラススコープで直接発生する場合、それはネストされたクラスとして扱われ、同様のルールが適用されます。11.7/1は次のように述べています。

ネストされたクラスはメンバーであるため、他のメンバーと同じアクセス権があります。

いずれにせよ、クラスのスコープ内で発生するラムダは、プライベートクラスメンバーにアクセスできます。だからあなたの例は大丈夫です。

(あなたが参照した投稿は、最終的には、 qualified-idによって指定された基本クラスの保護されたメンバーへのアクセスの問題に関するものでした。)

于 2013-02-10T23:54:29.387 に答える