型総称マクロ(_Generic)
C11から、ジェネリックが使えるようになりました。ジェネリックは、「型」を式にして、switch
文のような振る舞いをします。これを総称選択といい、型による処理のリストを総称関連といいます(62頁)。ジェネリックは、「ジェネリックス」「型総称」「総称型」などとも呼ばれています。
『Cクイックリファレンス』265頁
GetType(x)
マクロは、引数に渡された値の型を表示します。総称関連にない型、たとえばunsigned
やlong
など、マッチしない型はdefault:
が呼ばれます。
#include <stdio.h>
#define GetType(x) _Generic((x), \
int: "int", \
double: "double", \
char: "char", \
char*: "string", \
void*: "void*", \
default: "unknown" \
)
int main(void)
{
int d = 10;
double f = 1.41421356237;
char c = 'A';
char *s = "helo, world";
void *vp = &d;
long ld = 1234567890;
printf("Type: %s\n", GetType(d));
printf("Type: %s\n", GetType(f));
printf("Type: %s\n", GetType(c));
printf("Type: %s\n", GetType(s));
printf("Type: %s\n", GetType(vp));
printf("Type: %s\n", GetType(ld));
return 0;
}
$ ./a.out
Type: int
Type: double
Type: char
Type: string
Type: void*
Type: unknown
それぞれの型が表示されましたが、long
型は総称関連にないので、default
が実行されます。
もう少し役に立つプログラムを考えてみます。入力された値を型に合わせて二乗するプログラムです。GetSquared(x)
マクロは、総称選択でint
型ならgetSquaredInt()
関数を、double
型ならgetSquaredReal()
関数が呼ばれます。
#include <stdio.h>
#define GetSquared(x) _Generic((x), \
int: getSquaredInt, \
double: getSquaredReal \
)(x)
static int getSquaredInt(int n);
static double getSquaredReal(double n);
int main(void)
{
int n = 97;
printf("%d^2 = %d\n", n, GetSquared(n));
double r = 3.14159;
printf("%.2f^2 = %.2f\n", r, GetSquared(r));
return 0;
}
static int getSquaredInt(int n)
{
return n * n;
}
static double getSquaredReal(double n)
{
return n * n;
}
$ ./a.out
97^2 = 9409
3.141590^2 = 9.869588
Cには継承がないので、型の数だけ関数を書くことになります。簡単な処理であれば、マクロだけで完結してもいいかも知れません。
#define GetSquared(x) _Generic((x), \
int: x*x, \
double: x*x \
)(x)