2017-12-31 199 views
16

C++ 20'de önişlemci, bağımsız değişkenlerin sayısı sıfırdan büyükse, isteğe bağlı olarak değişken bir makrodaki simgeleri genişletmek için __VA_OPT__'u destekler. (Bu, taşınabilir olmayan ve çirkin bir hack olan ##__VA_ARGS__ GCC uzantısına olan ihtiyacı ortadan kaldırır.)__VA_OPT__ desteğini dikkatlice tespit edin?

Clang SVN bu özelliği uygulamıştır, ancak bunun için bir özellik sınama makrosu eklememişlerdir. Herhangi bir akıllı önişlemci hacker, sabit bir hataya veya taşınabilirlik uyarısına neden olmadan __VA_OPT__ desteğinin varlığını veya yokluğunu tespit etmenin bir yolunu bulabilir mi? gibi

cevap

20

chris's answer'den esinlenmiştir. __VA_OPT__ destekleniyorsa, üçüncü bağımsız değişken true yani

#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,) genişler; aksi halde, VA_OPT_SUPPORTED_I(?), PP_THIRD_ARG(__VA_OPT__(,),true,false,)'a genişler, üçüncü bağımsız değişken ise false olur.

+0

Bu, benim muhtemelen geliştirilebileceğini söylediğimde hayal ettiğim bir tür kıskançlık. Güzel iş :) – chris

+0

GÜZEL. Teşekkür ederim. –

5

şey onu geliştirmek mümkün olabilir olsa çalışmalıdır: Clang gövde üzerinde

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

, bu C++ 17 modunda C++ 2a modu ve 0 1 olarak değerlendirir. GCC trunk aslında bunu C++ 17'de 1'e kadar değerlendirir, ancak bu modda __VA_OPT__'u da işler. Bu ne yapar

bağımsız değişken sayısına dayalı _II ait _1 veya _2 versiyonunu ya çağırmak için kullanılması BOOST_PP_OVERLOAD olduğunu. __VA_OPT__(,), ,'a genişlerse, 2 boş argüman olacaktır. Değilse, 1 boş argüman olacaktır. Her zaman bu makroyu bir argüman listesiyle çağırırız, bu yüzden __VA_OPT__'u destekleyen herhangi bir derleyici her zaman ,'a genişletmelidir. Boost.PP bağımlılığı doğal olarak zorunlu değildir. Doğal olarak Boost.PP bağımlılığı zorunlu değildir. Basit bir 1 veya 2-arg OVERLOAD makrosu değiştirmek için yeterince kolay olmalıdır. genelliği biraz kaybetmek daha anlaşılır hale getirmek için:

#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 gelen uyarı amaçlı bir taşınabilirlik vardır:

uyarı: variadic makro C++ 98 [-WC++ 98- uyumsuzdur uyumluluk =

Bu algılamanın C++ 11 variadic makro desteği olmadan da mümkün olup olmadığını bilmiyorum. C++ 11'den daha düşük __cplusplus değerleri için destek almadığınızı düşünebilirsiniz, ancak Clang hala böyle bir çekle sarıldığında bile uyarı verir.

+0

bu cevabı kabul etmek isterdim, ama hiçbir bağımlılıkları ihtiyacım var ve yok "OVERLOAD" uygulamak için PP becerileri. Boost.PP bağımlılığı kaldırmak için bakım? –

+0

@EricNiebler, Tabii. Bu arada, [bu bir] (https://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments) dahil olmak üzere çeşitli SO soruları vardır. – chris

2

Diğer yanıtta da belirtildiği gibi, kendi OVERLOAD makronuzu yazabilirsiniz. BOOST_PP_OVERLOAD, iki parçadan oluşur, BOOST_PP_CAT ve BOOST_PP_VARIADIC_SIZE. Ancak, Boost'un aksine, sadece 2 adet arkıya dikkat ediyorsunuz.Yani:

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

Ve VARIADIC:

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

CAT gibi görünecek

#define VARIADIC(...) _VARIADIC_(__VA_ARGS__, 2, 1,) 
#define _VARIADIC_(e0, e1, size, ...) size