これはテンプレートを求めて叫びます。
class Example<class T>
{
...class definition...
};
あなたの質問の最後の部分への直接の答え-「私がもうマクロ定義にいないとしたら、どうすれば貼り付けと文字列化演算子を機能させることができますか」-は「できません」です。これらの演算子はマクロでのみ機能するため、機能させるにはマクロ呼び出しを作成する必要があります。
追加:
@mackenirは「テンプレートはオプションではない」と述べました。テンプレートがオプションではないのはなぜですか?このコードは、昔ながらの事前標準の事前テンプレートの方法でテンプレートをシミュレートしているため、多くの苦痛と悲しみを引き起こします。テンプレートを使用すると、変換操作はありますが、その苦痛を回避できます。
@mackenirは「マクロで物事を機能させる方法はありますか?」と尋ねました。はい、できますが、テンプレートを使用する必要があります。テンプレートの方が信頼性が高く、保守が容易です。マクロで機能させるには、含まれているヘッダーのコード内の関数名をマクロ呼び出しにする必要があります。これを正しく機能させるには、あるレベルの間接参照を実行する必要があります。
#define PASTE_NAME(x, y) PASTE_TOKENS(x, y)
#define PASTE_TOKENS(x, y) x ## y
#define TYPE_NAME Example
int PASTE_NAME(TYPE_NAME, _function_suffix)(void) { ... }
このレベルの間接参照は、トークン化演算子と文字列化演算子の両方でしばしば必要となるイディオムです。
@mackenirからの追加のコメントは、継続的な問題を示しています。具体的にしましょう。
現在、私はマクロを使用して、次のようにさまざまなクラスのフィールドとメソッドの束を定義しています。
class Example
{
// Use FIELDS_AND_METHODS macro to define some methods and fields
FIELDS_AND_METHODS(Example)
};
FIELDS_AND_METHODSは、文字列化およびトークン貼り付け演算子を使用する複数行のマクロです。
これを次のようなものに置き換えたいと思います
class Example
{
// Include FieldsNMethods.h, with TYPE_NAME preprocessor symbol
// defined, to achieve the same result as the macro.
#define TYPE_NAME Example
#include "FieldsNMethods.h"
};
わかった。これを具体的にするにFIELDS_AND_METHODS(type)
は、複数行でトークンの貼り付けを使用するマクロが必要です(ただし、文字列化については扱いません。同じ基本的なメカニズムが適用されます)。
#define FIELDS_AND_METHODS(type) \
type *next; \
type() : next(0) { } \
type * type ## _next() { return next; }
運が良ければ、これは「引数型へのポインタ」型のメンバー、その型のコンストラクタ、およびそのポインタを返すメソッド(この場合はExample_next)を宣言します。
したがって、これはマクロである可能性があり、「#include」が同等の仕事をするように置き換える必要があります。
fieldsNmethods.hの内容は次のようになります。
#ifndef TYPE_NAME
#error TYPE_NAME not defined
#endif
#define FNM_PASTE_NAME(x, y) FNM_PASTE_TOKENS(x, y)
#define FNM_PASTE_TOKENS(x, y) x ## y
TYPE_NAME *next;
TYPE_NAME() : next(0) { }
TYPE_NAME * FNM_PASTE_NAME(TYPE_NAME, _next)() { return next; }
#undef FNM_PASTE_NAME
#undef FNM_PASTE_TOKENS
ヘッダーには複数の包含ガードが含まれないことに注意してください。その存在理由は、それを複数回含めることができるようにすることです。また、ヘルパーマクロの定義を解除して、複数の包含を許可します(再定義は同一であるため、「良性」であり、エラーは発生しません)FNM_
。また、マクロのプリミティブ名前空間コントロールとしてプレフィックスを付けました。これにより、Cプリプロセッサに期待するコードが生成されます。G ++はウィッターしませんが、空のオブジェクトファイルを生成します(宣言された型は私のサンプルコードでは使用されていないため)。
これには、質問で概説されているものを除いて、呼び出し元のコードを変更する必要がないことに注意してください。SPOTの「信頼できる唯一の情報源」の原則(またはDRY「Do n'tRepeat Yourself」)を使用して、質問を改善する必要があると思います。
#define TYPE_NAME Example
class TYPE_NAME
{
// Include FieldsNMethods.h, with TYPE_NAME preprocessor symbol
// defined, to achieve the same result as the macro.
#include "FieldsNMethods.h"
};