2017-12-31 205 views
16

C++ 20では、引数の数がゼロより大きい場合、可変プロセッサマクロ内のトークンをオプションで展開する方法として、プリプロセッサが__VA_OPT__をサポートしています。 (これにより、移植性が低く、醜いハッキングである##__VA_ARGS__ GCC拡張が不要になります。)__VA_OPT__サポートを移植可能に検出しますか?

Clang SVNはこの機能を実装していますが、機能テストマクロを追加していません。賢明なプリプロセッサのハッカーは、ハードエラーや移植性の警告を引き起こすことなく__VA_OPT__のサポートの有無を検出する方法を見つけ出すことができますか?次のような

答えて

20

chris's answerからインスパイアされます。 __VA_OPT__がサポートされている場合は3番目の引数がtrueなるよう

#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_SUPPORTED_I(?)は、PP_THIRD_ARG(,,true,false,)に展開します。そうでない場合はVA_OPT_SUPPORTED_I(?)PP_THIRD_ARG(__VA_OPT__(,),true,false,)に、3番目の引数がfalseにそれぞれ展開されます。

+0

これは私が想像していたような簡潔さです。ニースの仕事:) – chris

+0

NICE。ありがとうございました。 –

5

何か作業をする必要があり、あなたはそれを改善することができるかもしれないけれども:クラントランクで

#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(?) 

を、これはC++ 17モードでC++ 2Aモードと0で1と評価されます。 GCCトランクは実際にはC++ 17でこれを1に評価しますが、そのモードでは__VA_OPT__も処理します。

これは、BOOST_PP_OVERLOADを使用して、引数の数に基づいて_II_1または_2バージョンを呼び出します。 __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__(,)) 

クランからの警告1つのポータビリティがある可変引数マクロはC++ 98 [-WC++との互換性がありませんが98-

この検出がC++ 11バリアブルマクロをサポートしていなくても可能かどうかわかりません。 __cplusplusの値がC++ 11より低いと仮定することも考えられますが、このようなチェックでラップされても警告は表示されます。

+0

私はこの答えを受け入れるのが大好きだが、私は何の依存関係を必要としない、と私は持っていません'OVERLOAD'を実装するPPスキル。 Boost.PP依存関係を取り除くためのケア? –

+0

@EricNiebler、確かに。その間、[この1つ](https://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments)を含むいくつかのSOの質問があります。 – chris

2

他の回答に記載されているように、独自のOVERLOADマクロを書くことができます。 BOOST_PP_OVERLOADは、2つの部分、BOOST_PP_CATBOOST_PP_VARIADIC_SIZEで構成されています。しかし、Boostとは異なり、あなたは約2つのargしか気にしません。だから、:

#define CAT(a, b) KITTY((a, b)) 
#define KITTY(par) MEOW ## par 
#define MEOW(a, b) a ## b 

そしてVARIADIC

#define OVERLOAD(prefix, ...) CAT(prefix, VARIADIC(__VA_ARGS__)) 

CATは次のようになります

#define VARIADIC(...) _VARIADIC_(__VA_ARGS__, 2, 1,) 
#define _VARIADIC_(e0, e1, size, ...) size 
関連する問題