芝士就是菜

芝士就是菜

公众号 芝士就是菜
zhihu
bilibili
youtube
twitter
github
email

震撼的事实!!!C言語でもジェネリックプログラミングが可能ですか??

今日は興味深い知識を見つけましたので、メモしておきます。皆さんご存知の通り、C 言語にはジェネリックがありませんが、C11 ではジェネリック選択式 (_ Generic) という新しい式が追加されました。これは何のためにあるのでしょうか?その目的は、式の型に基づいて値を選択することです。具体的な構文を見てみましょう。

ジェネリック選択式の導入#

まず、以下のコードを見てみましょう:

int main()
{
	int x = 1;
	double y = 2.0;
	char z = 'c';
	printf("%d\n", _Generic(x, int:0, double : 1, default:3));
	printf("%d\n", _Generic(y, int:0, double : 1, default:3));
	printf("%d\n",_Generic(z, int:0, double : 1, default:3));
	return 0;
}

_Genericは C11 のキーワードであり、丸括弧の中にはコンマで区切られた複数の項目が含まれます。最初の項目は式であり、後の各項目は型、コロン、値で構成されます(例:double: 1)。最初の項目の型に一致するタグに対して、式全体の値はその後ろの値になります。

実行結果は以下の通りです:

image.png

渡された変数の型に応じて、出力結果が異なることがわかります。最初の printf の最初の項目 x は int 型なので、式全体の結果は 0 になります。2 番目の printf の最初の項目は double 型なので、式の結果は 1 になります。3 番目の printf の結果は 3 ですが、char 型に一致するものがないため、デフォルトの default が選択されたためです。

実際には、これは switch 文に似ていますが、Generic は式の型に基づいてタグをマッチさせ、switch は式の値に基づいてタグをマッチさせます。

マクロ定義との組み合わせ#

上記の使用方法は少し面倒ですが、マクロ定義と組み合わせることで非常に便利になります。

例を見てみましょう:

#define MYTYPE(X) _Generic((X),int:"int", double:"double", default:"other")

int main()
{
	int d = 2;
	printf("%s\n", MYTYPE(d));
	printf("%s\n", MYTYPE(1.0*d));
	printf("%s\n", MYTYPE("string"));

	return 0;
}

実行結果は以下の通りです:

image.png

マクロ定義と組み合わせると、使いやすくなります。C++ のジェネリックプログラミングのような感じがしますが、まだ少し足りません。

上級プレイ#

_Generic タグに対応する値は、整数、文字列、関数ポインタのいずれかであることができます。

以下のコードを見てみましょう。

void PrintInt(int x)
{
	printf("%d\n", x);
}
void PrintDouble(double x)
{
	printf("%lf\n", x);
}
void PrintSting(char* x)
{
	printf("%s\n", x);
}

void PrintOther(void x)
{
	print("タイプが問題です\n");
}
#define PRINT(X) _Generic((X),\
	int:PrintInt,\
	double:PrintDouble,\
	const char*:PrintSting,\
	default:PrintOther)(X)

int main()
{	
	int x = 1;
	int y = 2.0;
	const char* str = "hello _Generic";
	PRINT(x);
	PRINT(y);
	PRINT(str);
	return 0;
}

実行結果は以下の通りです:

image.png

これで C++ のジェネリックプログラミングに似ていますね。面白いですが、やはり C++ のジェネリックの方が使いやすいです。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。