[C/C++]マクロのパラメータに関数ポインタを使用する

2181 ワード

typedefは、既存のタイプに対してより意味のある別名を作成するためのC/C++のキーワードです.通常のタイプでは、タイプは左、別名は右です.
typedef int size;

関数ポインタの定義もこのスタイルに一致する場合は、次のように定義するのが合理的です.
   typedef void(*)(int) Type;

しかし、実際にコンパイラは以下の定義方式を採用しています(以上のコードはコンパイルできません).
typedef void(*Ptr)(int);

理由については、void(*)(int)は確かに関数ポインタであり、タイプだと思いますが、名前はありません.typedefの本意は名前のタイプに別名を与えることです.このルールの下で最初の定義は明らかに違反しています.同様に配列の名前変更(本来は「typedef char[81]Line;形式的ですが、同じ理由ではできません):
   typedef char Line[81];

コンパイラが技術的に実現するのが難しいかどうかは、私にはわかりません.
本書のトピックに戻ると、関数ポインタのこの名前は、次のように、マクロの名前を変更するために使用できないことがわかりました.たとえば、マクロPtrTypeがタイプの名前を変更するために使用されます.

#define PtrType(_T, _Name) typedef _T _Name;


しかし、実践の結果は次のとおりです.

PtrType(void(int), Ptr)   //

PtrType(void(*)(int), Ptr)   //
PtrType(int, Ptr)         //

typedef void(*PTR)(int);

PtrType(PTR, Ptr)         //


では、上のマクロを有効にする方法はありますか?C++の発展に伴い,テンプレートの概念が提案されているが,関数ポインタをテンプレートの概念に適用すると,「void(int)」または「void(*)」(int)」が自身を表すことができなければ,有名なfunctionは使用上別の方法となるという問題がある.

function<int(int)> a; //

typdef int(*FT)(int); //
function<FT> a;


実際にテンプレート概念に適用すると,後の方式「FT」は「void」と認識される.不思議ですか?」FTはポインタなのに!
私たちはこのような概念上の同意がなぜなのかを追及しないで、またどれだけの理解しにくいことをもたらしました.しかし、この方法は私が本稿で提起したこの問題を解決することができます.テンプレートのこのプロパティを使用して、新しいタイプ定義記号:$を定義できます.

/**
* $,
*/
template<class _T> struct $
{
/**
*
*/
typedef _T Type;

/**
*
*/
typedef _T *Ptr;

/**
*
*/
typedef _T &Ref;
};


$の使い方は次のとおりです.

$<void(int)>::Ptr a = Print;
a(3);
$<int>::Type i = 0;
$<int>::Ref r = i;


この記号を使用して、前のPtrTypeを書き換えます.
#define PtrType(_T, _Name) typedef $<_T >::Ptr _Name;

これにより、関数ポインタをマクロの実装に使用できます.

PtrType(void(int), PTR)
PTR b = Print;
b(5);