2009-06-23 17 views
3

私は最近、Linuxに移植したいコードをいくつか取得しました。ヘッダーファイルでは、私は誰かが光を当てることを願っている好奇心が強いコードを持っています。ヘッダファイルの中で、他のクラスが定義されている名前空間の内部で、私は次のようしている:C++シングルトン作成問題

#define CREATE_SINGLETON_METHODS(s) \ 
    private: \ 
    friend class Singleton<c>; \ 
    ##c(); \ 
    virtual ~##c(); 

私は##トークン貼り付け操作ですが、私は、なぜ原作者(誰を把握することはできませんことを理解私は知らないし、接触することができない)それを使用した。私はこのようになります実装クラスを持っている:

class MapManager : public Singleton<MapManager> { 
CREATE_SINGLETON_METHODS(MapManager) 

private: 
... 

私はコンパイルするとき、私は次のエラーを取得する:

error: pasting ";" and "MapManager" does not give a valid preprocessing token

これは、Windows上で見つけるとgccのいくつかの以前のバージョン(前4コンパイル。バツ)。何がここで起こっている可能性についての任意のアイデア?ありがとう!

答えて

-1

これは自動シングルトン作成時の試行がうまくいかないようです。一般的には、仮想関数や仮想継承に巧妙なテンプレート技法をつけておくことができれば、マクロを使わなくても可能です。

私があなただったら、影響を受けたクラスの関連コードを手作業で書き直すだけです。マクロはこのようなものにとって悪いニュースです。

1

コンストラクタが役に立たない前に##のように見えます。デストラクタ上のものは、チルダを型名に貼り付けることを目的としています。おそらく元の著者はコピー&ペーストされており、古いバージョンであるためコンパイルエラーが発生しなかったので、エラーをキャッチしませんでした。

1

はこれにマクロを変更してみてください:

#define CREATE_SINGLETON_METHODS(c) \ 
    private: \ 
    friend class Singleton<c>; \ 
    c(); // Note the change on this line! \ 
    virtual ~##c(); 

私は##事業者の一つを取り出しました。 ";"のように見える"c();とマージされました。 gcc 4.

+0

これは、プリプロセッサの違いに過ぎません。 – Dolphin

+0

右 - それがポイントです。gcc4のプリプロセッサがトークン「Singleton ;」を貼り付けるように見えます「c();」の展開は、 ##演算子を見ると一緒になります。この演算子は不要ですが、単純な修正は単に削除することです。 – Naaff

+0

デストラクタでのトークンの貼り付けも間違っています。デストラクタの名前は、トークン「〜」とクラス名の順に付けられます。たとえそれらの間に空白を入れずに書かれていても、貼り合わせる必要はありません。 – Doug

0

これはどのコンパイラでもコンパイルできましたか?まず第一に、それはおそらく次のようになります。

#define CREATE_SINGLETON_METHODS(c) \ 
    private: \ 
    friend class Singleton<c>; \ 
    ##c(); \ 
    virtual ~##c(); 

私はそれが友人のクラスを定義しているマクロのパラメータ、プライベートコンストラクタとデストラクタプライベートだと仮定しているので。

+0

はい、それは正しいです。私は質問に入ったときにタイプミスがありましたが、それ以外はすべて正しいです。 これはどのようにコンパイルするのか分かりませんが、Windows(Visual C++ 8.0)では苦情なしでコンパイルされます。 –

1

私はいつもこの種のプリプロセッサ「魔法」(ゴミを読む)がそれ以上の問題を引き起こすことが分かります。場合によっては、それは必要な悪ですが、私はここに当てはまるとは思わない。私はコード内のそのインスタンスを書き換えて、その恐ろしいものを排除したいと思います。

2

私は自分の一般的なシングルトンのテンプレートを使用します。 は、このテンプレートでこれらの不快なマクロを交換してみてください:

#ifndef SINGLETON_HPP_STYLET 
#define SINGLETON_HPP_STYLET 0 


/* 
* 
* 
* Generic Singleton implementation 
* 
* 
*/ 


     template <class T> 
     class SingletonHolder : public T 
     { 
      public:         
       static SingletonHolder<T>& getInstance() 
       { 

        static SingletonHolder<T> instance; 
        return instance; 
       } 

      private: 
       SingletonHolder() 
       { 
       }; 

       virtual ~SingletonHolder() 
       { 
       }; 

     };//class SingletonHolder 



#endif //SINGLETON_HPP_STYLET 

// ----------------- -------------------------------------------------

USAGE:

クラス工ass。

typedef SingletonHolder<SomeClass> SomeClassSingleton; 


SomeClassSingleton::getInstance().doSomething(); 
1

「文字列化」とトークンペースト(「# 『と』 ##」)のためのプリプロセッサ演算子のみ確実マクロパラメータに使用することができます。また、すべての場合にそれらを動作させるためには、間接レベルを使用する必要があります(特に、それ自身のマクロを使用する場合)。

は、いくつかの追加の詳細については、

を参照してください。

1

私はまったく同じ問題を抱えていました。実行してみましょう:

グラム++ -E mytestfile.hプリプロセッサの結果が何であるかを確認するために、コマンドライン上で(もちろん、独自のファイル名を使用して)

。何が起こっているのかを示すのに役立つかもしれません。私はgcc 3.4.4を実行していて、4.xでしか起こっていないものと同じエラーが発生します(Visual Studio 2008では正常に動作しますが)。トークナイザを排除

は、問題を解決します:

#define CREATE_SINGLETON_METHODS(c) \ 
private: \ 
friend class Singleton<c>; \ 
c(); \ 
virtual ~c(); 

このコードは私に(-Eオプションと私のコマンドラインからコピー)プリプロセッサの結果として、次のようになります:

private: friend class Singleton<MapManager>; MapManager(); virtual ~MapManager(); 

コンパイラは満足しています。 http://gcc.gnu.org/onlinedocs/gcc-4.0.4/cpp/Tokenization.htmlによると

Once the input file is broken into tokens, the token boundaries never change, except when the `##' preprocessing operator is used to paste tokens together. The compiler does not re-tokenize the preprocessor's output. Each preprocessing token becomes one compiler token.

は '##' は、この場合、トークン化ルールを破ります。エラーが発生するたびに、プリプロセッサはコンパイラに "; MapManager()"が設定されているトークンを与えていた可能性がありますが、4.xコンパイラは明らかにそうではありません。

そして、ここでいくつかの情報フォーム(http://gcc.gnu.org/onlinedocs/cpp/Concatenation.html#Concatenation)も注目に値する:

It is common to find unnecessary uses of '##' in complex macros. If you get this warning, it is likely that you can simply remove the '##'.

お役に立てば幸いです。