9

次のコードを検討してください。

#include <iostream>

struct X {
    int foo() {
        // Can I get this to be an instance-specific static variable, please?
        static int i = 0;
        return i++;
    }
};

int main() {
    X a, b;
    std::cout << a.foo() << ' ';
    std::cout << b.foo() << ' ';
    std::cout << b.foo() << '\n';
    // output is: 0 1 2
    // desired output: 0 0 1
}

宣言と初期化を遠く離れたヘッダーとコンストラクターに移動する必要なく、iインスタンスごとにこの静的変数のコピーを取得することは可能ですか?X

これが必要な理由は、この変数の値がこの特定の関数内でのみ関連するためです (しかし、それがメンバー関数であるインスタンスにも固有です)。たとえば、最後の呼び出しパラメーター、最後の呼び出しの時刻などです。

このアイデアの背後にあるクラスは、すでにある程度大きくなっており、1 つの関数内で使用されるそのような小さな変数の宣言と初期化が見苦しくなっています。

更新:メモリをリークしたくないことに注意してください。インスタンスが破棄されると、それに関連付けられている変数も削除する必要があります。

Update²:明らかに (そして残念ながら) この正確なセマンティクスを持つ適切な言語機能は実際にはありません。いくつかの回避策がありますが、それぞれに制限と落とし穴があります。

  • 「関数」宣言と定義の配置
  • 他の「実際の」メンバー変数へのアクセス
  • 派生クラスで「関数」をオーバーロードする
  • ...

これらの意味を念頭に置いて、頭に浮かぶ最初のことを固守するのが最も効率的であるように思われます。

struct A {
    int j = 0;
    int i = 0;
    int foo() { return i++ + j++; }
};

このようなものに行くのではなく:

struct B {
    int j = 0;
    std::function<int()> foo = 
        [this, i = 0]() mutable { return i++ + this->j++; };
};

またはこれ:

struct C {
    int j;
    struct Foo {
        int i; 
        C *c;
        Foo(C *c) : i(), c(c) {}
        int operator() () { return i++ + c->j++; }
    } foo;
    C() : j(), foo(this) {}
};

またはこれ:

struct D {
   int j = 0;
   std::map<std::string, int> i;
   int foo() { return i[__PRETTY_FUNCTION__]++ + j++; }
};

または類似。

コメントと回答をありがとうございます!

4

9 に答える 9

4

おそらくこれはあなたが望むものです:

struct X {
    X() : i(0) {}  // initialize variable on construction

    int foo() {
        // Can I get this to be an instance-static variable, please?
        return i++;
    }

    int i; // instance variable
};

編集:単純なオプションを探していない人のための、メンバー変数のない代替:

typedef std::map<X*,int> XMap;
static XMap xMap;

struct X {
    X() { xMap.insert(this, 0); }
    ~X() { xMap.erase(this); }

    int foo() {
        return xMap[this]++;
    }
};

編集:上記と同じですが、コンストラクタ/デストラクタはありません:

struct X {
    int foo() {
        return xMap[this]++;  // same as below:
        // XMap::iterator it = xMap.find(this);
        // if (it == xMap.end())
        // {
        //     it = xMap.insert(XMap::value_type(this, 0)).first;
        // }
        // return *it++;
    }
};
于 2013-04-26T12:10:07.817 に答える
1

fooの唯一の方法ですかX?カウンターを作成する便利な方法が必要なようです:

#include <functional>

std::function<int()> create_counter()
{
    int i = 0;
    return [=]() mutable { return i++; };
}

#include <iostream>

int main()
{
    auto a = create_counter();
    auto b = create_counter();

    std::cout << a() << '\n';
    std::cout << a() << '\n';
    std::cout << b() << '\n';
    std::cout << b() << '\n';
    std::cout << b() << '\n';
    std::cout << b() << '\n';
    std::cout << a() << '\n';
}

Xヒント:やなどの名前の使用を控えると、より適切な回答が得られますfoo;-)

于 2013-04-26T12:15:54.463 に答える
0

ここに別のオプションがあります。概念的にはあまりきれいではありませんが、かなり単純なままで、関数と変数を近づけるという技術的な問題を処理します。

struct XFoo {
    XFoo() : i(0) { }

    int foo() { return i++; }

    private:
        int i;
};

struct X : XFoo {
  // lots of stuff here
};

または C++11 の場合:

struct XFoo {
    int foo() { return i++; }

    private:
        int i = 0;
};
于 2013-04-26T14:02:41.593 に答える
0

GetVariableI(X)X のインスタンスを受け取り、インスタンス固有の値、または null が渡されたときに静的な値を返すメソッドを作成できます。

そのアプローチはあなたの問題を解決するはずですが、それはばかげています。それはあなたが望むことをしますが、ほとんどの場合、あなたが必要とするものではありません. あなたが達成しようとしている行動は何ですか?達成しようとしていることについて詳しく説明していただければ、別の (そして健全な) 解決策を提供できます。

于 2013-04-26T12:19:21.577 に答える
0

KnuthのLiterate Programmingを参照してください。このようなことをしました。基本的に、テキストを移動できるマクロ言語が必要です。

于 2013-04-26T12:31:52.203 に答える