最近流行りの名前付き引数(ラベル付き引数やパラメータ名とも呼ばれる)ですが、C言語はもとよりC++ですらいまだにこの機能をサポートしていません。
そんなわけで、今回はC言語/C++言語(Clang)でこの名前付き引数を無理やり実現する方法を紹介します。
構造体を使う
typedef struct { int location; int length; } Range;
Range range = {.location = 1, .length = 3};
構造体は上記のように{.メンバ名 = 初期値}
という形式で初期化することも可能です。
この初期化式を関数の引数に応用すれば、名前付き引数っぽい仕組みを実現出来ます。
typedef struct { int location; int length; } Range;
void print(Range range) { printf("%d, %d", range.location, range.length); }
int main() {
print((Range){.location = 1, .length = 3}); // それっぽい
}
(Range)
の型キャストが不格好ですが、C++(Clang)であればキャストは省略可能です。
int main() {
print({.location = 1, .length = 3});
}
マクロを使えばよりそれらしくなります。
#define PRINT_RANGE(...) print((Range){__VA_ARGS__})
int main() {
PRINT_RANGE(.location = 1, .length = 3);
}
Named Parameter Idiom
余談ですが、オブジェクト指向言語ではメソッドチェーンを用いることで、名前付き引数とある程度同等の要件を満たすことが出来ます。
Range r = Range().setLocation(1).setLength(3);
HTTP().set_type("POST")
.set_url("http://sample")
.set_cookie("monster")
.add_param("q", "hello")
.add_param("lang", "Japan")
.send();
備考
ちなみに、今回紹介したイディオムを用いれば、以下の様な、よりわかり易い書き方が出来ます。
HTTP({
.type = "POST",
.url = "http://sample",
.cookie = "monster",
.params = {
{"q" , "hello"},
{"lang", "Japan"},
}
});
ただ「一部のメンバをオプション扱いにしたい」といった要件を満たす際には複雑な工夫が必要になるため、「Named Parameter Idiom」の利用がオススメです。