2012-12-12 34 views
72

कहते हैं कि हम इसकॉमा ++ मैक्रो

#define FOO(type,name) type name 

की तरह एक मैक्रो कौन सा हम जैसे

FOO(int, int_var); 

इस्तेमाल कर सकते हैं है लेकिन हमेशा की तरह बस उस के रूप में:

FOO(std::map<int, int>, map_var); // error: macro "FOO" passed 3 arguments, but takes just 2 

बेशक हम कर सकते थे:

typedef std::map<int, int> map_int_int_t; 
FOO(map_int_int_t, map_var); // OK 

जो बहुत ergonomic नहीं है। प्लस प्रकार असंगतताओं के साथ निपटा जाना है। मैक्रो के साथ इसे हल करने का कोई विचार है? अन्यथा

#define SINGLE_ARG(...) __VA_ARGS__ 
#define FOO(type,name) type name 

FOO(SINGLE_ARG(std::map<int, int>), map_var); 

, ताकि उसे कुछ अतिरिक्त थकाऊ है::

+0

मुझे लगता है कि आपको अक्षर बनाने के लिए पात्रों से बचना होगा। – Jite

+0

कम से कम सी ++ में, आप कहीं भी टाइपपीफ डाल सकते हैं, इसलिए मुझे यकीन नहीं है कि आप क्यों कहते हैं कि इसे "पहले से" होना चाहिए। –

उत्तर

78

क्योंकि कोण कोष्ठक भी प्रतिनिधित्व करते हैं (या में होते हैं) कर सकते हैं तुलना ऑपरेटरों <, >, <= और >=, मैक्रो विस्तार कोष्ठक कोष्ठक के अंदर कोण ब्रैकेट के अंदर अल्पविराम को अनदेखा नहीं कर सकता है। (यह भी वर्ग कोष्ठक और ब्रेसिज़ के लिए एक समस्या है, भले ही उन आम तौर पर संतुलित जोड़े होते हैं।) आप कोष्ठक में मैक्रो तर्क संलग्न कर सकते हैं:

FOO((std::map<int, int>), map_var); 

समस्या तो है कि पैरामीटर मैक्रो में किसी एक parenthesized रहता है विस्तार, जो इसे अधिकांश संदर्भों में एक प्रकार के रूप में पढ़ने से रोकता है।

template<typename T> struct argument_type; 
template<typename T, typename U> struct argument_type<T(U)> { typedef U type; }; 
#define FOO(t,name) argument_type<void(t)>::type name 
FOO((std::map<int, int>), map_var); 

क्योंकि समारोह प्रकार के गठन अतिरिक्त कोष्ठक पर ध्यान नहीं देता, तो आप इस मैक्रो का उपयोग कर सकते हैं:

एक अच्छा चाल इस समाधान करने के लिए कि सी ++ में, आप एक समारोह प्रकार का उपयोग कर एक parenthesized प्रकार नाम से एक typename निकाल सकते हैं है के साथ या बिना कोष्ठकों जहां प्रकार का नाम एक अल्पविराम शामिल नहीं है:

FOO((int), int_var); 
FOO(int, int_var2); 

सी में, ज़ाहिर है, इस आवश्यक नहीं है क्योंकि प्रकार के नाम कोष्ठक के बाहर अल्पविराम नहीं कर सकते हैं। तो, एक क्रॉस-भाषा मैक्रो के लिए आप लिख सकते हैं:

#ifdef __cplusplus__ 
template<typename T> struct argument_type; 
template<typename T, typename U> struct argument_type<T(U)> { typedef U type; }; 
#define FOO(t,name) argument_type<void(t)>::type name 
#else 
#define FOO(t,name) t name 
#endif 
+0

यह कमाल है। लेकिन आप इसके बारे में कैसे पता लगाया? मैं कई सारी चालों की कोशिश कर रहा हूं और कभी सोचा नहीं कि एक समारोह का प्रकार इस मुद्दे को ठीक करेगा। –

+0

@ विलियम कस्टोड जैसा कि मुझे याद है, मैं सबसे अधिक परेशान पार्स समस्या के संदर्भ में फ़ंक्शन प्रकारों और फ़ंक्शन घोषणाओं के व्याकरण का अध्ययन कर रहा था, इसलिए यह सौभाग्यपूर्ण था कि मुझे पता था कि अनावश्यक कोष्ठक उस संदर्भ में किसी प्रकार पर लागू किए जा सकते हैं। – ecatmur

+0

टेम्पलेट्स के साथ काम करते समय मुझे इस विधि के साथ एक समस्या मिली।आइए मान लें कि मैं जो कोड चाहता था वह था: 'टेम्पलेट <क्लास की टाइप टाइप, क्लास वैल्यू टाइप> शून्य कुछ फनक (खाद्य (std :: map ) तत्व) {}' यदि मैं यहां इस समाधान को लागू करता हूं, तो structs मैक्रो के पीछे निर्भर प्रकार बन जाते हैं, और टाइपनाम उपसर्ग अब प्रकार पर आवश्यक है। आप इसे जोड़ सकते हैं, लेकिन कटौती टाइप कर दिया गया है, इसलिए अब आपको फ़ंक्शन को कॉल करने के लिए प्रकार तर्कों को मैन्युअल रूप से सूचीबद्ध करना होगा। मैं कॉमा के लिए एक मैक्रो को परिभाषित करने के मंदिर की विधि का उपयोग कर समाप्त हुआ। यह सुंदर दिखता नहीं है, लेकिन यह पूरी तरह से काम किया। –

38

अपने पूर्वप्रक्रमक variadic मैक्रो का समर्थन करता है, तो

#define SINGLE_ARG2(A,B) A,B 
#define SINGLE_ARG3(A,B,C) A,B,C 
// as many as you'll need 

FOO(SINGLE_ARG2(std::map<int, int>), map_var); 
+0

ओह, भगवान ... क्यों? क्यों न केवल कोष्ठक में संलग्न है? –

+11

@VladLazarenko: क्योंकि आप हमेशा कोष्ठक में कोड के मनमानी टुकड़े नहीं डाल सकते हैं। विशेष रूप से, आप एक घोषणाकर्ता में प्रकार के नाम के चारों ओर कोष्ठक नहीं डाल सकते हैं, जो वास्तव में यह तर्क बन जाता है। –

+1

... और यह भी क्योंकि आप केवल मैक्रो _definition_ को संशोधित करने में सक्षम हो सकते हैं और उन सभी स्थानों को नहीं कह सकते हैं (जो आपके नियंत्रण में नहीं हो सकते हैं, या फ़ाइलों के 1000s में फैले हुए हो सकते हैं)। ऐसा होता है, उदाहरण के लिए, एक समान नामित फ़ंक्शन से कर्तव्यों को लेने के लिए मैक्रो जोड़ते समय। – BeeOnRope

2

ऐसा करने के लिए कम से कम दो तरीके हैं। सबसे पहले, आप एक मैक्रो कि कई तर्क लेता है परिभाषित कर सकते हैं:

#define FOO2(type1, type2, name) type1, type2, name 

अगर आप आप पा सकते हैं कि है कि आप अधिक तर्क को संभालने के लिए अधिक मैक्रो को परिभाषित खत्म करो।

दूसरे, आप तर्क के आसपास कोष्ठक रख सकते हैं:

#define FOO(type, name) type name 
F00((std::map<int, int>) map_var; 

अगर आप आप पा सकते हैं कि कि अतिरिक्त कोष्ठकों परिणाम की वाक्य रचना अप पेंच है।

+0

पहले समाधान के लिए, प्रत्येक मैक्रो के पास एक अलग नाम होना चाहिए, क्योंकि मैक्रोज़ ओवरलोड नहीं होते हैं। और दूसरे के लिए, यदि आप किसी प्रकार के नाम से गुज़र रहे हैं, तो एक बहुत अच्छा मौका है कि इसका उपयोग एक चर (या टाइपिफ़) घोषित करने के लिए किया जाएगा, इसलिए कोष्ठक समस्याएं पैदा करेंगे। –

1

सरल उत्तर यह है कि आप नहीं कर सकते हैं। टेम्पलेट तर्कों के लिए यह <...> की पसंद का दुष्प्रभाव है; < और > असंतुलित संदर्भों में भी दिखाई देते हैं ताकि मैक्रो तंत्र को संभालने के लिए विस्तारित नहीं किया जा सके जैसे कि यह ब्रांड्स को संभालता है। (समिति के सदस्यों में से कुछ एक अलग टोकन के लिए तर्क दिया था, कहते हैं कि (^...^), पर वे <...> का उपयोग कर समस्याओं के बहुमत को समझाने के लिए सक्षम नहीं थे।)

2

यह संभव है P99 साथ:

#include "p99/p99.h" 
#define FOO(...) P99_ALLBUTLAST(__VA_ARGS__) P99_LAST(__VA_ARGS__) 
FOO() 

कोड को प्रभावी ढंग से ऊपर तर्क सूची में केवल पिछले अल्पविराम स्ट्रिप्स। clang -E के साथ जांचें (पी 99 को एक सी 99 कंपाइलर की आवश्यकता है)।

81

आप कोष्ठक का उपयोग नहीं कर सकता है और आप माइक SINGLE_ARG समाधान पसंद नहीं है, सिर्फ एक अल्पविराम को परिभाषित:

#define COMMA , 

FOO(std::map<int COMMA int>, map_var); 

यह भी मदद करता है अगर आप मैक्रो तर्क के कुछ stringify करना चाहते हैं,

में के रूप में
#include <cstdio> 
#include <map> 
#include <typeinfo> 

#define STRV(...) #__VA_ARGS__ 
#define COMMA , 
#define FOO(type, bar) bar(STRV(type) \ 
    " has typeid name \"%s\"", typeid(type).name()) 

int main() 
{ 
    FOO(std::map<int COMMA int>, std::printf); 
} 

जो std::map<int , int> has typeid name "St3mapIiiSt4lessIiESaISt4pairIKiiEEE" प्रिंट करता है।

+9

# कॉम्मा वाह परिभाषित करें, आपने अभी मुझे काम के घंटे बचाए हैं ... मैंने इस साल पहले क्यों नहीं सोचा था। इस विचार को साझा करने के लिए धन्यवाद। यह मुझे मैक्रोज़ बनाने की इजाजत दे रहा है जो विभिन्न तर्कों के साथ सेटअप सेटअप पूरी तरह से मायने रखता है। – moliad

+14

डरावनी – namezero

+0

के लिए प्लस 1 काम नहीं करता है यदि आप तर्क को स्ट्रिंग करना चाहते हैं ... – kiw

12

बस FOO रूप

#define UNPACK(...) __VA_ARGS__ 

#define FOO(type, name) UNPACK type name 

फिर प्रकार तर्क है, उदा आसपास कोष्ठक के साथ हमेशा यह आह्वान को परिभाषित

FOO((std::map<int, int>), map_var); 

यह निश्चित रूप से एक अच्छा विचार मैक्रो परिभाषा पर एक टिप्पणी में आमंत्रण का उदाहरण देना हो सकता है।

+0

यह सुनिश्चित नहीं है कि यह इतना दूर क्यों है, यह माइक सेमुर्स की तुलना में बहुत अच्छा समाधान है। यह उपयोगकर्ता से त्वरित और सरल और पूरी तरह छुपा हुआ है। – iFreilicht

+1

@iFreilicht: इसे एक साल बाद थोड़ा सा पोस्ट किया गया था। ;-) –

+1

और क्योंकि यह समझना मुश्किल है कि यह कैसे और क्यों काम करता है – VinGarcia