このコードを考えてみましょう:
#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__
#define G(...) F(__VA_ARGS__)
F(1, 2, 3)
G(1, 2, 3)
予想される出力はX = 1 and VA_ARGS = 2, 3
両方のマクロで、GCCを使用してこれを実現していますが、MSVCはこれを次のように展開します。
X = 1 and VA_ARGS = 2, 3
X = 1, 2, 3 and VA_ARGS =
あれは、 __VA_ARGS__
は、複数の引数に分解されるのではなく、単一の引数として展開されます。
これを回避する方法はありますか?
MSVCのプリプロセッサは、標準仕様とはかなり異なる動作をするようです。
おそらく、次の回避策が役立ちます。
#define EXPAND( x ) x
#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__
#define G(...) EXPAND( F(__VA_ARGS__) )
私が投稿した 次のMicrosoftサポートの問題 :
次のプログラムでは、プリコンパイラーが
__VA_ARGS__
を誤って展開するため、コンパイルエラーが発生します。#include <stdio.h> #define A2(a1, a2) ((a1)+(a2)) #define A_VA(...) A2(__VA_ARGS__) int main(int argc, char *argv[]) { printf("%d\n", A_VA(1, 2)); return 0; }
プリプロセッサは、printfを次のように展開します。printf( "%d\n"、((1、2)+()));
printf( "%d\n"の代わりに、((1)+(2)));
Microsoftコンパイラチームの開発者から、次の満足のいく答えを受け取りました。
こんにちは:この場合、Visual C++コンパイラーは正しく動作しています。最初のマクロ呼び出しで「...」に一致するトークンが結合されて単一のエンティティ(16.3/p12)を形成するという規則と、サブマクロが引数置換の前に展開される(16.3.1/p1)という規則を組み合わせる場合)次に、この場合、コンパイラは、A2が単一の引数で呼び出されたと見なします。したがって、エラーメッセージです。
どのバージョンのMSVCを使用していますか? Visual C++ 2010が必要です。
__VA_ARGS__
はC99で最初に導入されました。 MSVCはC99をサポートしようとしたことがないため、サポートは追加されませんでした。
ただし、現在、__VA_ARGS__
は新しいC++標準であるC++ 2011(以前はC++ 0xと呼ばれていました)に含まれています。Microsoftはこれをサポートする予定であるため、最近のバージョンのMSVCでサポートされています。
ところで、このサポートを受けるには、ソースファイルに.cpp
サフィックスを使用する必要があります。 MSVCはCフロントエンドを長い間更新していません。