1

CS の学生にグループ番号を変更させてから、その番号に関連するものを生成させる必要があります。学生にはあまり変更してほしくありませんが、どこかで定義された 1 つのグループ番号だけを

#define GROUP_NUM 0

ただし、その MACRO から残りを生成する方法が見つかりません。例えば:

#include <iostream>
using namespace std;

// string troubles
#define STR(x) #x
#define XSTR(x) STR(x)

// the trouble
#define GROUP_NUM 0
#define CLASS_NAME Group GROUP_NUM
#define CLASS_STR XSTR(CLASS_NAME)

int main()
{
   cout << "CLASS_NAME = " << CLASS_STR << endl; 

   return 0;
}

悲しいことに出力

CLASS_NAME = Group 0

ここでの問題は、次のようなクラスを作成するために CLASS_NAME を使用する必要があるため、 Group0の間にそのスペースが必要ないことです。

class CLASS_NAME : public .... { ... }

使ってみた

#define CLASS_NAME Group##GROUP_NUM

しかし、その後 GROUP_NUM は展開されず、出力されます

CLASS_NAME = GroupGROUP_NUM

私が見つけた唯一の解決策は、これらの CLASS_NAME と CLASS_STR を、引数としてグループ番号を渡されるマクロ関数として定義することです (別のマクロではなく、呼び出しサイトで!):

// the trouble
#define GROUP_NUM 0
#define CLASS_NAME(g) Group ## g
#define CLASS_STR(g) XSTR(CLASS_NAME(g))

int main()
{
   cout << "CLASS_NAME = " << CLASS_STR(GROUP_NUM) << endl; 

   return 0;
}

より良い解決策はありますか?以下が展開されないのはなぜですか?

#define CLASS_STR XSTR(CLASS_NAME(GROUP_NUM))

上記のXSTRの定義は、チェーンされたマクロを使用できることを示しているように見えるので、ここで展開されない理由がわかりません。

更新: ヘルパー マクロ関数のトリックが解決策です。ただし、解決策を明確にしたいと思います。

  1. マクロ展開トリックはどのように機能しますか? 直接完全に拡張するのか、それとも 1 ラウンドだけ拡張するのか? (つまり、複雑なマクロを使用している場合、ヘルパー関数のレイヤーが複数必要になるということでしょうか?)
  2. ## による展開は、私にはまだ少し不思議です。

私の完全な問題は、nori フレームワーク、特にthisに関係していました。そのマクロを使用すると、つまり

#define NORI_REGISTER_CLASS(cls, name) \
    cls *cls ##_create(const PropertyList &list) { \
        return new cls(list); \
    } \
    static struct cls ##_{ \
        cls ##_() { \
            NoriObjectFactory::registerClass(name, cls ##_create); \
        } \
    } cls ##__;

NORI_REGISTER_CLASS(CLASS_NAME, "mystring") を使用すると、誤って部分的に展開されてしまいます

Group0 * CLASS_NAME_create (const PropertyList &list) { return new Group0 (list); } ...

しかし、1 つのラッパー マクロを使用してそのマクロを呼び出すと、機能します。ここでのマクロ展開のルールは何ですか? 最初の cls が展開され、2 番目の cls が名前を保持するのはなぜですか?

4

3 に答える 3

3

考えられる解決策は次のとおりです。

#include <iostream>

using namespace std;

#define CLASS_NUM 0

// String macros
#define XSTR(x) STR(x)
#define STR(x) #x

#define CONCAT(x,y) x##y
// XCONCAT will first process tokens before passing them to CONCAT
#define XCONCAT(x,y) CONCAT(x,y)

// This will generate Group0
#define CLASS_NAME XCONCAT(Group,CLASS_NUM)

// Then this will generate "Group0"
#define CLASS_STR XSTR(CLASS_NAME)

int main()
{
   cout << "CLASS_NAME = " << CLASS_STR << endl; 

   return 0;
}

このコードを使用すると、出力は次のようになります。

CLASS_NAME = Group0
于 2013-08-13T18:18:24.240 に答える
2

オペレーターは##トークンに対してのみ機能します。したがって、ヘルパー マクロが必要です。

これを試して:

#include <ostream>
#include <iostream>

// the trouble
using namespace std;
// the trouble
// string troubles
#define STR(x) #x
#define XSTR(x) STR(x)
#define GROUP_NUM 0
#define CLASS_STR(g) XSTR(Group ## g)
#define CLASS_STR2(g) CLASS_STR(g)

int main()
{
   cout << "CLASS_NAME = " << CLASS_STR2(GROUP_NUM) << endl; 

   return 0;
}
于 2013-08-13T18:20:19.163 に答える
1

これに使用BOOST_PP_CATします:

#define CLASS_NAME BOOST_PP_CAT(Group,GROUP_NUM)

http://www.boost.org/doc/libs/1_54_0/libs/preprocessor/doc/ref/cat.html

于 2013-08-13T18:17:43.870 に答える