C++ 20では、プリプロセッサは、引数の数がゼロより大きい場合にオプションで可変マクロのトークンを展開する方法として __VA_OPT__
をサポートします。 (これにより、移植性のないいハックである##__VA_ARGS__
GCC拡張機能が不要になります。)
Clang SVNはこの機能を実装していますが、機能テストマクロは追加していません。賢いプリプロセッサハッカーは、ハードエラーや移植性の警告を発生させることなく、__VA_OPT__
サポートの有無を検出する方法を見つけることができますか?
クリスの答え に触発されました。
_#define PP_THIRD_ARG(a,b,c,...) c
#define VA_OPT_SUPPORTED_I(...) PP_THIRD_ARG(__VA_OPT__(,),true,false,)
#define VA_OPT_SUPPORTED VA_OPT_SUPPORTED_I(?)
_
___VA_OPT__
_がサポートされている場合、VA_OPT_SUPPORTED_I(?)
はPP_THIRD_ARG(,,true,false,)
に展開されるため、3番目の引数はtrue
です。それ以外の場合、VA_OPT_SUPPORTED_I(?)
はPP_THIRD_ARG(__VA_OPT__(,),true,false,)
に展開され、3番目の引数はfalse
です。
次のようなものが動作するはずですが、改善できるかもしれません。
_#include <boost/preprocessor.hpp>
#define VA_OPT_SUPPORTED_II_1(_) 0
#define VA_OPT_SUPPORTED_II_2(_1, _2) 1
#define VA_OPT_SUPPORTED_I(...) BOOST_PP_OVERLOAD(VA_OPT_SUPPORTED_II_, __VA_OPT__(,))(__VA_OPT__(,))
#define VA_OPT_SUPPORTED VA_OPT_SUPPORTED_I(?)
_
Clangトランクでは、これはC++ 2aモードでは1、C++ 17モードでは0と評価されます。 GCCトランクは実際にはC++ 17でこれを1と評価しますが、そのモードで___VA_OPT__
_も処理します。
これは、_BOOST_PP_OVERLOAD
_を使用して、引数の数に基づいて__1
_または__2
_バージョンの__II
_バージョンを呼び出します。 __VA_OPT__(,)
が_,
_に展開される場合、2つの空の引数があります。そうでない場合、1つの空の引数があります。このマクロは常に引数リストで呼び出すため、___VA_OPT__
_をサポートするコンパイラーは常に_,
_に展開する必要があります。
当然、Boost.PP依存関係は必須ではありません。単純な1-or-2-arg OVERLOAD
マクロは、簡単に置き換えられるはずです。より簡単にするために少し一般性を失います:
_#define OVERLOAD2_I(_1, _2, NAME, ...) NAME
#define OVERLOAD2(NAME1, NAME2, ...) OVERLOAD2_I(__VA_ARGS__, NAME2, NAME1)
#define VA_OPT_SUPPORTED_I(...) OVERLOAD2(VA_OPT_SUPPORTED_II_1, VA_OPT_SUPPORTED_II_2, __VA_OPT__(,))(__VA_OPT__(,))
_
Clangから移植性に関する警告が1つあります。
警告:可変長マクロはC++ 98と互換性がありません[-Wc ++ 98-compat-pedantic]
この検出がC++ 11の可変長マクロのサポートなしでも可能かどうかはわかりません。 C++ 11よりも低い___cplusplus
_値のサポートはないと想定することもできますが、そのようなチェックでラップされた場合でもClangは警告を表示します。
他の回答で述べたように、独自のOVERLOAD
マクロを書くことができます。 BOOST_PP_OVERLOAD
は2つの部分で構成され、BOOST_PP_CAT
およびBOOST_PP_VARIADIC_SIZE
。ただし、Boostとは異なり、2つの引数のみを考慮します。そう:
#define OVERLOAD(prefix, ...) CAT(prefix, VARIADIC(__VA_ARGS__))
CAT
は次のようになります。
#define CAT(a, b) KITTY((a, b))
#define KITTY(par) MEOW ## par
#define MEOW(a, b) a ## b
VARIADIC
:
#define VARIADIC(...) _VARIADIC_(__VA_ARGS__, 2, 1,)
#define _VARIADIC_(e0, e1, size, ...) size