2017-12-31 170 views
16

सी ++ 20 में, प्रीप्रोसेसर __VA_OPT__ को वैकल्पिक रूप से एक भिन्न मैक्रो में टोकन का विस्तार करने के तरीके के रूप में समर्थन करता है यदि तर्क की संख्या शून्य से अधिक है। (यह ##__VA_ARGS__ जीसीसी एक्सटेंशन की आवश्यकता को रोकता है, जो एक गैर-पोर्टेबल और बदसूरत हैक है।)पोर्टेबल रूप से __VA_OPT__ समर्थन का पता लगाएं?

क्लैंग एसवीएन ने इस सुविधा को लागू किया है, लेकिन उन्होंने इसके लिए एक फीचर टेस्ट मैक्रो नहीं जोड़ा है। क्या कोई चालाक प्रीप्रोसेसर हैकर कठोर त्रुटि या पोर्टेबिलिटी चेतावनी के बिना __VA_OPT__ समर्थन की उपस्थिति या अनुपस्थिति का पता लगाने का एक तरीका समझ सकता है?

उत्तर

20

chris's answer से प्रेरित हो गया।

#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,) के लिए विस्तारित तो तीसरा तर्क true है; अन्यथा, VA_OPT_SUPPORTED_I(?)PP_THIRD_ARG(__VA_OPT__(,),true,false,) तक फैला है, तीसरा तर्क false है।

+0

यह वह प्रकार है जिसकी मैं कल्पना कर रहा था जब मैंने कहा कि मेरा शायद सुधार किया जा सकता है। अच्छा काम :) – chris

+0

नाइस। धन्यवाद। –

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

बजना ट्रंक पर, यह सी ++ 2 ए मोड और 0 सी ++ 17 मोड में में 1 करने के लिए मूल्यांकन करता है। जीसीसी ट्रंक वास्तव में सी ++ 17 में 1 का मूल्यांकन करता है, लेकिन उस मोड में __VA_OPT__ को भी संभालता है।

यह क्या करता है उपयोग BOOST_PP_OVERLOAD_II के दोनों _1 या _2 संस्करण तर्क की संख्या के आधार कॉल करने के लिए है। यदि __VA_OPT__(,), तक फैला है, तो 2 खाली तर्क होंगे। यदि नहीं, तो 1 खाली तर्क होगा। हम हमेशा इस मैक्रो को एक तर्क सूची के साथ कहते हैं, इसलिए __VA_OPT__ का समर्थन करने वाला कोई भी कंपाइलर हमेशा इसे , पर विस्तारित करना चाहिए।

स्वाभाविक रूप से, Boost.PP निर्भरता अनिवार्य नहीं है। एक साधारण 1-या-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__(,)) 

वहाँ एक पोर्टेबिलिटी बजना से चेतावनी है:

चेतावनी: variadic मैक्रो के सी ++ 98 [-WC++ 98 असंगत हैं compat-pedantic]

मुझे नहीं पता कि यह पहचान सी ++ 11 वैरिएडिक मैक्रो समर्थन के बिना भी संभव है या नहीं। आप C12+ 11 से कम __cplusplus मानों के लिए कोई समर्थन नहीं मान सकते हैं, लेकिन क्लैंग अभी भी इस तरह की जांच में लपेटने पर भी चेतावनी देता है।

+0

मैं इस जवाब को स्वीकार करना अच्छा लगेगा, लेकिन मैं कोई निर्भरता की जरूरत है, और मैं नहीं है 'ओवरवर्क्स 'को लागू करने के लिए पीपी कौशल। बूस्ट.पीपी निर्भरता को हटाने की देखभाल? –

+0

@EricNiebler, ज़रूर। इस बीच, कई SO प्रश्न हैं, जिनमें [यह एक] शामिल है (https://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments)। – chris

2

जैसा कि दूसरे उत्तर में बताया गया है, आप अपना खुद का OVERLOAD मैक्रो लिख सकते हैं। BOOST_PP_OVERLOAD में दो भाग होते हैं, BOOST_PP_CAT और BOOST_PP_VARIADIC_SIZE। हालांकि, बूस्ट के विपरीत, आप केवल 2 तर्कों की परवाह करते हैं।तो:

#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 
संबंधित मुद्दे