マクロの可変個実引数の型を強制する

今回は単なる思いつきを備忘録として書き留めておくだけの内容です。過信はしないでください。

#define foo(...)

上のような省略記号を持つマクロの場合、省略記号の部分に指定した実引数を扱うには、__VA_ARGS__を使う必要があります。それ以前にマクロですので、関数原型のように型を指定できるわけでもなく、実引数の型を強制する方法は原則としてありません。それがよいところでもあり、悪いところでもあるのがマクロというものです。

今回は、そうしたマクロの特徴にあえて歯向かい、実引数の型を(関数と同程度に)強制しようという試みです。

#define foo(...) \
        (sizeof((struct {int a;double b; const char* s;}){__VA_ARGS__}), /* 以下省略 */)

上記のようにすれば、第1引数はint型に暗黙的に変換できなければなりませんのでスカラ型でなければならず、第2引数はdouble型に暗黙的に変換できなければなりませんので算術型でなければならず、第3引数はconst char*型に暗黙的に変換できなければなりませんので整数型かポインタ型でなければなりません。また、個数は1〜3個でなければなりません。

C++なら、関数の多重定義や省略時実引数が使えますので、複合リテラルの代わりに関数呼出し(ただし、sizeofのオペランドなので評価されない)でもよいと思います。tupleを使うのもよいでしょう。

この記事のトラックバックURL:

http://www.kijineko.co.jp/trackback/738

名前付きの実引数が実現できるかも...

かなり前に書いた「可変個数の実引数の個数」や、本日書いた「マクロの可変個実引数の型を強制する」では、複合リテラルを使って何ができるかを模索しているわけです。この手のネタは

既存の関数に応用すると...

printfのように、整数も浮動小数点数もポインタも扱うような場合は無理ですが、execlのような関数なら、次のように置き換えてしまった方が安全な気がします。

#define execl(path, ...)   execv((path), (char*[]){__VA_ARGS__, NULL})

最後のNULLがやや冗長ですが、NULLを忘れたときの安全対策だと思えば、この程度なら安いものでしょう。

このエントリーを含むはてなブックマーク