1

コードの一定量の重要なコンポーネントに使用するテンプレート Singleton クラスがあります。シングルトン コード モデルを使用することは、この質問のポイントではありません。

ここで、このテンプレートを使用するすべてのクラスで共有される静的カウンターをこのクラスに追加したいと思います。あなたのためにそれをコーディングさせてください(コードは網羅的ではありません):

template <class T>
class Singleton
{
public:
   Singleton(const std::string &name){ 
      printf("%s CTOR call #%d\n", name.c_str(), _counter);  
      _counter++; 
   }
   virtual ~Singleton(){}
private:
   static int _counter; // I want this to be shared by all classes
}

// I can only initialize it like this; sadly
template<class T> 
int Singleton<T>::_counter = 0;

// main code (simplified):
Singleton<MyClass1>("MyClass1") c1;
Singleton<MyClass2>("MyClass2") c2;
Singleton<MyClass3>("MyClass3") c3;
Singleton<MyClass4>("MyClass4") c4;

期待される出力:

MyClass1 CTOR call #0
MyClass2 CTOR call #1 // counter is incremented
MyClass3 CTOR call #2
MyClass4 CTOR call #3

私が得るものは次のとおりです。

MyClass1 CTOR call #0
MyClass2 CTOR call #0 // counter is not incremented
MyClass3 CTOR call #0
MyClass4 CTOR call #0

つまり、静的 int は共有されず、各クラスに固有です。

テンプレート クラスに「非テンプレート」カウンターを含めるにはどうすればよいですか? これはヘッダーのみのテンプレートで可能ですか?

4

3 に答える 3

4

Counter内部static変数を持つ別のクラスを持つことができます。したがって、これは「ネストされた静的」カウントに似ています:)。

シンタックス シュガーの場合は、opeartor ++必要なものをオーバーロードします。

以下は、それを行う主な方法です。

struct Counter
{
  static unsigned int value;
  Counter& operator ++ (int) { value ++; return *this; }
  operator unsigned int () const { return value; }
};
unsigned int Counter::value = 0;

template <class T>
class Singleton
{
public:
   Singleton(const std::string &name){ 
      printf("%s CTOR call #%d\n", name.c_str(), s_counter.value);  
      s_counter++; 
   }   
   virtual ~Singleton(){}
private:
   static Counter s_counter; // shared by all classes
};

これが実際のデモです。

Udpate : これは、別の .cpp ファイルで定義する必要のないヘッダーのみのテンプレートファイルを「強制」する別の方法です。Counter::valueしかし、私は上記を好むでしょう。

template<bool _true>
struct Counter
{
  static unsigned int value;
  Counter& operator ++ (int) { value ++; return *this; }
  operator unsigned int () const { return value; }
};
template<bool _true>
unsigned int Counter<_true>::value = 0;

template<>
struct Counter<false>; // disable the other alternative so no one can invoke it

template <class T>
class Singleton
{
public:
   Singleton(const std::string &name){ 
      printf("%s CTOR call #%d\n", name.c_str(), s_counter.value);  
      s_counter++; 
   }   
   virtual ~Singleton(){}
private:
   static Counter<true> s_counter; // shared by all classes
};
template<class T>
Counter<true> Singleton<T>::s_counter;
于 2012-10-08T09:34:57.183 に答える
3

ヘッダーのみが必要なため、カウンターを別のクラスに入れ、それをテンプレートにすることもできます。例:

template <class T> 
struct Helper
{
  static int _counter;
};

template<class T>
int Helper<T>::_counter = 0;

struct Dummy{};

template <class T> 
class Singleton 
{ 
public: 
   Singleton(const std::string &name){  
     printf("%s CTOR call #%d\n", name.c_str(), Helper<Dummy>::_counter);   
     Helper<Dummy>::_counter++;  
   } 
   virtual ~Singleton(){} 
};

Nimのソリューションと比較して編集してください。これはもちろん、あまりにも複雑です..しかし、テンプレートを学習するための練習と考えてください

于 2012-10-08T09:26:58.893 に答える
1

次のように:

static int& counter()
{
  static int _counter = 0;
  return _counter;
}

これをシングルトンのメンバーにし、メンバー変数の代わりにこれを使用します...

編集:あなたの質問を読み直しました。これを別のタイプのメンバーにする必要があります。

struct Counter
{
   static int& counter()
   {
     static int _counter = 0;
     return _counter;
   }
};

template <class T>
class Singleton
{
public:
   Singleton(const std::string &name){ 
      std::cout << name <<Counter::counter() << std::endl;
      Counter::counter()++;
   }
   virtual ~Singleton(){}
private:
};
于 2012-10-08T09:26:15.290 に答える