C言語で名前付き引数を実現する方法(ラベル/パラメータ付き引数)

最近流行りの名前付き引数(ラベル付き引数やパラメータ名とも呼ばれる)ですが、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」の利用がオススメです。

広告
広告