सी ++ मैक्रोज़ के साथ वैकल्पिक पैरामीटर


105

क्या सी ++ मैक्रोज़ के साथ वैकल्पिक पैरामीटर प्राप्त करने का कोई तरीका है? किसी तरह का ओवरलोडिंग भी अच्छा होगा।


1
C के लिए समान: stackoverflow.com/questions/11761703/… प्रीप्रोसेसरों के मूल रूप से समान होने के बाद भी ऐसा ही होना चाहिए: stackoverflow.com/questions/5085533/…
Ciro Santilli 郝海东 冠状 over 事件 法轮功

हो सकता है कि फंक्शन ओवरलोड, डिफॉल्ट पैरामीटर, वैरेडिक टेम्प्लेट या संभवतः नामित पैरामीटर मुहावरा हो जो आप देख रहे हैं
smoothware

कृपया अपने चुने हुए उत्तर को वास्तविक समाधानों के साथ उच्च-उत्थान वाले लोगों के लिए अपडेट करें, न कि नीच-उत्थान वाले एक कहावत परNo you can't
अल्बर्ट रेनशॉ

जवाबों:


158

यहाँ यह करने का एक तरीका है। यह दो बार तर्कों की सूची का उपयोग करता है, पहले हेल्पर मैक्रो का नाम बनाने के लिए, और फिर उस हेल्पर मैक्रो के लिए तर्कों को पास करने के लिए। यह एक मैक्रो को तर्कों की संख्या की गणना करने के लिए एक मानक चाल का उपयोग करता है।

enum
{
    plain = 0,
    bold = 1,
    italic = 2
};

void PrintString(const char* message, int size, int style)
{
}

#define PRINT_STRING_1_ARGS(message)              PrintString(message, 0, 0)
#define PRINT_STRING_2_ARGS(message, size)        PrintString(message, size, 0)
#define PRINT_STRING_3_ARGS(message, size, style) PrintString(message, size, style)

#define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4
#define PRINT_STRING_MACRO_CHOOSER(...) \
    GET_4TH_ARG(__VA_ARGS__, PRINT_STRING_3_ARGS, \
                PRINT_STRING_2_ARGS, PRINT_STRING_1_ARGS, )

#define PRINT_STRING(...) PRINT_STRING_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)

int main(int argc, char * const argv[])
{
    PRINT_STRING("Hello, World!");
    PRINT_STRING("Hello, World!", 18);
    PRINT_STRING("Hello, World!", 18, bold);

    return 0;
}

यह मैक्रो के कॉलर के लिए आसान बनाता है, लेकिन लेखक के लिए नहीं।


1
यह बहुत अच्छा है, लेकिन मुझे नहीं लगता कि अगर मैं सिर्फ PRINT_STRING करता तो यह काम करता। उस स्थिति में एक डिफ़ॉल्ट प्रिंट आउट नहीं होगा (और यह वास्तव में वह मामला है जिसका मैं उपयोग करना चाहता हूं)। अभी भी वास्तव में अच्छा के लिए +1।
सेनोक

2
मेरे लिए gcc में काम करता है (और यह बहुत चालाक है!) :-) लेकिन विजुअल स्टूडियो में मेरे लिए काम नहीं करता है :-(
टिम ग्रैडवेल

3
@TimGradwell - यह MSVC कंपाइलर में एक बग के कारण है जिसे उन्होंने स्वीकार किया है लेकिन लगभग एक दशक में तय नहीं किया है। हालाँकि, वर्कअराउंड उपलब्ध हैं
मधुमक्खी पालन

चालाक, लेकिन 'GET_4th_ARG' में आपके द्वारा चलाए जा रहे 'पुश आउट' की वजह से वैकल्पिक वैरिएड मैक्रो तर्कों के लिए काम नहीं करता है।
Searchengine27

क्या इसकी PRINT_STRING_MACRO_CHOOSERभी जरूरत है? क्या मैं इसके आंतरिक शरीर को सीधे बदल सकता हूं और इस पूरी चीज को कॉल कर सकता हूं (__VA_ARGS__)?
हेरगोट

85

अपने जवाब के लिए डेरेक लेडबेटर के साथ बहुत सम्मान के साथ - और एक पुराने प्रश्न को पुनर्जीवित करने के लिए माफी के साथ।

यह क्या कर रहा था की समझ पाने के लिए और कहीं और से आगे बढ़ाने की क्षमता के __VA_ARGS__साथ ##मुझे एक बदलाव के साथ आने की अनुमति दी ...

// The multiple macros that you would need anyway [as per: Crazy Eddie]
#define XXX_0()                     <code for no arguments> 
#define XXX_1(A)                    <code for one argument> 
#define XXX_2(A,B)                  <code for two arguments> 
#define XXX_3(A,B,C)                <code for three arguments> 
#define XXX_4(A,B,C,D)              <code for four arguments>  

// The interim macro that simply strips the excess and ends up with the required macro
#define XXX_X(x,A,B,C,D,FUNC, ...)  FUNC  

// The macro that the programmer uses 
#define XXX(...)                    XXX_X(,##__VA_ARGS__,\
                                          XXX_4(__VA_ARGS__),\
                                          XXX_3(__VA_ARGS__),\
                                          XXX_2(__VA_ARGS__),\
                                          XXX_1(__VA_ARGS__),\
                                          XXX_0(__VA_ARGS__)\
                                         ) 

मेरे जैसे गैर-विशेषज्ञों के लिए, जो जवाब पर ठोकर खाते हैं, लेकिन यह देख नहीं सकते कि यह कैसे काम करता है, मैं वास्तविक प्रसंस्करण के माध्यम से कदम रखूंगा, जो निम्नलिखित कोड के साथ शुरू होता है ...

XXX();
XXX(1); 
XXX(1,2); 
XXX(1,2,3); 
XXX(1,2,3,4); 
XXX(1,2,3,4,5);      // Not actually valid, but included to show the process 

हो जाता है ...

XXX_X(, XXX_4(), XXX_3(),  XXX_2(),    XXX_1(),      XXX_0()         );
XXX_X(, 1,       XXX_4(1), XXX_3(1),   XXX_2(1),     XXX_1(1),       XXX_0(1)          );
XXX_X(, 1,       2,        XXX_4(1,2), XXX_3(1,2),   XXX_2(1,2),     XXX_1(1,2),       XXX_0(1,2)        );
XXX_X(, 1,       2,        3,          XXX_4(1,2,3), XXX_3(1,2,3),   XXX_2(1,2,3),     XXX_1(1,2,3),     XXX_0(1,2,3)      );
XXX_X(, 1,       2,        3,          4,            XXX_4(1,2,3,4), XXX_3(1,2,3,4),   XXX_2(1,2,3,4),   XXX_1(1,2,3,4),   XXX_0(1,2,3,4)    );
XXX_X(, 1,       2,        3,          4,            5,              XXX_4(1,2,3,4,5), XXX_3(1,2,3,4,5), XXX_2(1,2,3,4,5), XXX_1(1,2,3,4,5), XXX_0(1,2,3,4,5) );

जो सिर्फ छठा तर्क बन जाता है ...

XXX_0(); 
XXX_1(1); 
XXX_2(1,2); 
XXX_3(1,2,3); 
XXX_4(1,2,3,4); 
5; 

पुनश्च: संकलन त्रुटि प्राप्त करने के लिए XXX_0 के लिए #define निकालें [अर्थात: यदि कोई तर्क-वितर्क विकल्प की अनुमति नहीं है]।

PPS: अमान्य स्थितियों के लिए अच्छा होगा (जैसे: 5) कुछ ऐसा हो जो प्रोग्रामर को एक स्पष्ट संकलन त्रुटि दे!

PPPS: मैं एक विशेषज्ञ नहीं हूं, इसलिए मुझे टिप्पणियाँ (अच्छी, बुरी या अन्य) सुनकर बहुत खुशी हो रही है!


3
आप एक स्पष्ट संकलन त्रुटि प्राप्त कर सकते हैं यदि आप चयनित तर्क को परिवर्तित करते हैं जो # (पाउंड चिन्ह) का उपयोग करके स्ट्रिंग के लिए एक MACRO नाम माना जाता है और इसकी तुलना पहले से अपेक्षित उपसर्ग के साथ n वर्ण है और यदि कोई मेल नहीं है, तो एक जानकारीपूर्ण मुद्रित। त्रुटि।
AturSams

1
वाह, मुझे नहीं पता कि यह काम करता है, लेकिन यह कम से कम बहुत रचनात्मक है!
सीमित प्रायश्चित

4
पहला तर्क हमेशा खाली क्यों होता है? क्यों हम इसे नहीं छोड़ सकते: XXX_X(,##__VA_ARGS__,` ... XXX_X (,, XXX_4 (), XXX_3 (), XXX_2 (), XXX_1 (), XXX_0 ()); `
रहमान

2
खाली पहला तर्क (अल्पविराम) महत्वपूर्ण है। ## __ VA_ARGS__ अगर यह अल्पविराम से पहले है - तो यह अल्पविराम को हटा देता है यदि ## __ VA_ARGS__ कुछ भी नहीं है। आप इसे "बीकोम्स ..." उदाहरण में देख सकते हैं कि पहली (कोई तर्क नहीं) लाइन के केवल 6 पैरामीटर हैं लेकिन बाकी को 7 मिलते हैं। यह चाल सुनिश्चित करती है कि कोई तर्क स्थिति काम न करे
डेविड सोरकोव्स्की

@ ईरिक - यह Microsoft कंपाइलरों में एक बग के कारण है, लेकिन आप इस प्रश्न को वर्कअराउंड के लिए देख सकते हैं
मधुमक्खी पालन

31

C ++ मैक्रोज़ C. से परिवर्तित नहीं हुआ है, क्योंकि C में फ़ंक्शंस के लिए ओवरलोडिंग और डिफ़ॉल्ट तर्क नहीं थे, यह निश्चित रूप से उन्हें मैक्रोज़ के लिए नहीं था। तो आपके सवाल का जवाब देने के लिए: नहीं, उन सुविधाओं में मैक्रोज़ मौजूद नहीं हैं। आपका एकमात्र विकल्प कई मैक्रोज़ को अलग-अलग नामों से परिभाषित करना है (या मैक्रोज़ का उपयोग न करें)।

एक विचार के रूप में: C ++ में आम तौर पर जितना संभव हो उतना मैक्रोज़ से दूर जाने के लिए अच्छा अभ्यास माना जाता है। यदि आपको इस तरह की सुविधाओं की आवश्यकता है, तो एक अच्छा मौका है जब आप मैक्रोज़ का उपयोग कर रहे हैं।


4
ध्यान दें कि कारण यह है कि "अधिभार" मैक्रोज़ के लिए असंभव है क्योंकि उनके पास कोई अंतर्निहित प्रकार नहीं है। मैक्रोज़ का बस विस्तार होता है।
1:12 बजे mk12

2
यद्यपि मैं मैक्रोज़ का उपयोग यथासंभव कम करता हूं, मैंने पाया कि ट्रेस आउटपुट के माध्यम से डिबगिंग बहुत आसान हो जाता है जैसे __FILE__और चीजों के साथ __LINE__... और
क्रिश्चियन सेवेरिन

अच्छा जवाब नहीं। यह एक अच्छा जवाब है: stackoverflow.com/q/27049491/893406
v.oddou

सशर्त संकलन और डिबगिंग / लॉगिंग वह डोमेन है जहां मैक्रोज़ वास्तव में बहुत आसान और वैध हैं। हर गंभीर प्रोग्रामर इसे जानता है। स्थिरांक को परिभाषित करने और कंटेनर टेम्पलेट बनाने के लिए कुछ पागल सी स्तर कोडिंग सामान करने से मैक्रो का उपयोग करने से दूर होने के लिए अच्छा अभ्यास क्या है। काश C ++ मैक्रोज़ के लिए और भी सुविधाएँ जोड़ देता। वे टेम्पलेट्स के लिए रूढ़िवादी हैं। पाठ्यक्रम का सर्वश्रेष्ठ कोडलेट्स होगा जो मुझे डोमेन विशिष्ट भाषा (पहलुओं) के लिए कंपाइलर में जनरेटर जोड़ने की अनुमति देता है।
लोथर

1
मुझे भी लगता है कि यह एक अच्छा जवाब नहीं है, क्योंकि एक मैक्रो पूरी तरह से किसी भी सी ++ भाषा विकल्प के अलावा अन्य है, क्योंकि इसे संकलक से पहले ही संभाला जाएगा। तो आप अन्य काम कर सकते हैं, और कोई भी कंपाइलर या लिंकर कोड को ऑप्टिमाइज़ नहीं करना चाहिए, क्योंकि शायद इसका ऑप्टिमाइज़ेशन नहीं करना है।
अलबमजैक

26

डेरेक लेडबेटेर , डेविड सोर्कोवस्की , अपने उत्तरों के लिए सिफरलेट के साथ सबसे बड़े सम्मान के साथ , जेन्स गुस्टेड द्वारा खाली मैक्रो तर्कों का पता लगाने के लिए सरल विधि के साथ। पर

https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/

अंत में मैं एक ऐसी चीज के साथ बाहर आता हूं जिसमें सभी चालें शामिल हैं, ताकि समाधान हो

  1. फ़ंक्शन ओवरलोडिंग को प्राप्त करने के लिए केवल मानक C99 मैक्रोज़ का उपयोग करता है , इसमें कोई GCC / CLANG / MSVC एक्सटेंशन शामिल नहीं है (यानी, , ##__VA_ARGS__GCC / CLANG के लिए विशिष्ट अभिव्यक्ति द्वारा निगल रहा अल्पविराम , और ##__VA_ARGS__MSVC के लिए अंतर्निहित निगल )। तो बेझिझक गुज़रे ज़माने को याद करो--std=c99 यदि आप चाहें तो अपने संकलक को )
  2. शून्य तर्क के लिए काम करता है , साथ ही असीमित संख्या में तर्क भी , यदि आप इसे अपनी आवश्यकताओं के अनुरूप आगे बढ़ाते हैं
  3. उचित रूप से क्रॉस-प्लेटफ़ॉर्म पर काम करता है , कम से कम के लिए परीक्षण किया गया

    • जीएनयू / लिनक्स + जीसीसी (GCC 4.9.2 CentOS 7.0 x86_64 पर)
    • GNU / Linux + CLANG / LLVM , (CLANG / LLVM 3.5.0 CentOS 7.0 x86_64 पर)
    • OS X + Xcode , (XCode 6.1.1 OS X Yosemite 10.10.1 पर)
    • विंडोज + विजुअल स्टूडियो , (विंडोज 7 SP1 64 बिट्स पर विजुअल स्टूडियो 2013 अपडेट 4)

Lazies के लिए, स्रोत की प्रतिलिपि बनाने के लिए बस इस पोस्ट के अंतिम पर जाएं। नीचे विस्तृत विवरण दिया गया है, जो सभी लोगों को __VA_ARGS__मेरे जैसे सामान्य समाधानों की तलाश में मदद करता है। =)

यहाँ है कि यह कैसे जाता है। सबसे पहले उपयोगकर्ता के लिए दृश्यमान अतिभारित "समारोह" को परिभाषित, मैं इसे नाम दिया है create, और संबंधित वास्तविक समारोह परिभाषा realCreate, और तर्क के विभिन्न संख्या के साथ मैक्रो परिभाषाओं CREATE_2, CREATE_1, CREATE_0, नीचे दिखाया गया है:

#define create(...) MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)

void realCreate(int x, int y)
{
  printf("(%d, %d)\n", x, y);
}

#define CREATE_2(x, y) realCreate(x, y)
#define CREATE_1(x) CREATE_2(x, 0)
#define CREATE_0() CREATE_1(0)

MACRO_CHOOSER(__VA_ARGS__)भाग अंततः मैक्रो परिभाषा के नाम पर ले कर जाता है, और दूसरा (__VA_ARGS__)हिस्सा उनके पैरामीटर सूचियों शामिल हैं। तो एक उपयोगकर्ता के कॉल को create(10)हल करने के लिए CREATE_1(10), CREATE_1भाग से आता है MACRO_CHOOSER(__VA_ARGS__), और (10)भाग दूसरे से आता है(__VA_ARGS__)

MACRO_CHOOSERट्रिक का उपयोग करता है, यदि __VA_ARGS__खाली है, तो निम्नलिखित अभिव्यक्ति को प्रीप्रोसेसर द्वारा वैध मैक्रो कॉल में समाहित किया गया है:

NO_ARG_EXPANDER __VA_ARGS__ ()  // simply shrinks to NO_ARG_EXPANDER()

स्वाभाविक रूप से, हम इस परिणामी मैक्रो कॉल को परिभाषित कर सकते हैं

#define NO_ARG_EXPANDER() ,,CREATE_0

दो अल्पविरामों पर ध्यान दें, उन्हें जल्द ही समझाया गया है। अगला उपयोगी मैक्रो है

#define MACRO_CHOOSER(...) CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER __VA_ARGS__ ())

इसलिए की कॉल

create();
create(10);
create(20, 20);

वास्तव में विस्तारित हैं

CHOOSE_FROM_ARG_COUNT(,,CREATE_0)();
CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER 10 ())(10);
CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER 20, 20 ())(20, 20);

जैसा कि मैक्रो नाम से पता चलता है, हम बाद में तर्कों की संख्या की गणना कर रहे हैं। यहां एक और चाल आती है: प्रीप्रोसेसर केवल सरल पाठ प्रतिस्थापन करता है। यह कोष्ठक के अंदर देखे जाने वाले कॉमा की संख्या से एक मैक्रो कॉल के तर्कों की संख्या को कम करता है। अल्पविराम द्वारा अलग किए गए वास्तविक "तर्कों" को वैध सिंटैक्स की आवश्यकता नहीं है। वे कोई भी पाठ हो सकते हैं। यह कहना है, उपरोक्त उदाहरण में, NO_ARG_EXPANDER 10 ()मध्य कॉल के लिए 1 तर्क के रूप में गिना जाता है। NO_ARG_EXPANDER 20तथा20 () क्रमशः नीचे कॉल के लिए 2 तर्क के रूप में गिना जाता है।

यदि हम आगे के विस्तार के लिए निम्नलिखित हेल्पर मैक्रोज़ का उपयोग करते हैं

##define CHOOSE_FROM_ARG_COUNT(...) \
  FUNC_RECOMPOSER((__VA_ARGS__, CREATE_2, CREATE_1, ))
#define FUNC_RECOMPOSER(argsWithParentheses) \
  FUNC_CHOOSER argsWithParentheses

GCC / CLANG के लिए काम के ,बाद की अनुगामी CREATE_1, एक (झूठी सकारात्मक) त्रुटि को दबाते हुए कह रही है किISO C99 requires rest arguments to be used जब -pedanticआपके कंपाइलर के पास जा रहे हों। FUNC_RECOMPOSERMSVC के लिए एक काम के आसपास है, या इसे सही ढंग से मैक्रो कॉल की कोष्ठकों के अंदर तर्क की संख्या (यानी, अल्पविराम) गिनती नहीं कर सकते हैं। इसके परिणामों का और समाधान किया जाता है

FUNC_CHOOSER (,,CREATE_0, CREATE_2, CREATE_1, )();
FUNC_CHOOSER (NO_ARG_EXPANDER 10 (), CREATE_2, CREATE_1, )(10);
FUNC_CHOOSER (NO_ARG_EXPANDER 20, 20 (), CREATE_2, CREATE_1, )(20, 20);

जैसा कि ईगल-आइड, आपने देखा होगा, अंतिम आवश्यकता केवल एक कदम है जो एक मानक तर्क गिनती चाल को नियोजित करने के लिए है जो अंत में वांछित मैक्रो संस्करण के नाम को चुनना है:

#define FUNC_CHOOSER(_f1, _f2, _f3, ...) _f3

जो परिणामों को हल करता है

CREATE_0();
CREATE_1(10);
CREATE_2(20, 20);

और निश्चित रूप से हमें वांछित, वास्तविक फ़ंक्शन कॉल देता है:

realCreate(0, 0);
realCreate(10, 10);
realCreate(20, 20);

सभी को एक साथ रखना, बेहतर पठनीयता के लिए बयानों के कुछ पुनर्व्यवस्था के साथ, 2-तर्क उदाहरण का पूरा स्रोत का यहां है:

#include <stdio.h>

void realCreate(int x, int y)
{
  printf("(%d, %d)\n", x, y);
}

#define CREATE_2(x, y) realCreate(x, y)
#define CREATE_1(x) CREATE_2(x, 0)
#define CREATE_0() CREATE_1(0)

#define FUNC_CHOOSER(_f1, _f2, _f3, ...) _f3
#define FUNC_RECOMPOSER(argsWithParentheses) FUNC_CHOOSER argsWithParentheses
#define CHOOSE_FROM_ARG_COUNT(...) FUNC_RECOMPOSER((__VA_ARGS__, CREATE_2, CREATE_1, ))
#define NO_ARG_EXPANDER() ,,CREATE_0
#define MACRO_CHOOSER(...) CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER __VA_ARGS__ ())
#define create(...) MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)

int main()
{
  create();
  create(10);
  create(20, 20);
  //create(30, 30, 30);  // Compilation error
  return 0;
}

हालांकि, जटिल, बदसूरत, एपीआई डेवलपर पर बोझ डालते हुए, हमें पागल लोगों के लिए C / C ++ फ़ंक्शन के वैकल्पिक मापदंडों को ओवरलोड करने और स्थापित करने का एक समाधान आता है। आने वाले ओवरलोड एपीआई का उपयोग बहुत सुखद और सुखद हो जाता है। =)

यदि इस दृष्टिकोण का कोई और संभव सरलीकरण है, तो कृपया मुझे बताएं

https://github.com/jason-deng/C99FunctionOverload

फिर से सभी शानदार लोगों के लिए विशेष धन्यवाद जिन्होंने मुझे प्रेरित किया और मुझे इस काम को प्राप्त करने के लिए प्रेरित किया! =)


3
3 या 4 कार्यों में इसका विस्तार कैसे होता है?
फेयलिडा

@Phylliida ideone.com/jD0Hm5 - शून्य से पांच तर्कों का समर्थन किया।
xx

9

किसी को भी दर्द के लिए कुछ VA_NARGS समाधान की खोज जो Visual C ++ के साथ काम करता है। निम्नलिखित मैक्रो ने मेरे लिए दोषपूर्ण (शून्य मापदंडों के साथ भी) दृश्य c ++ एक्सप्रेस 2010 में काम किया:

#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,N,...) N
#define VA_NUM_ARGS_IMPL_(tuple) VA_NUM_ARGS_IMPL tuple
#define VA_NARGS(...)  bool(#__VA_ARGS__) ? (VA_NUM_ARGS_IMPL_((__VA_ARGS__, 24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1))) : 0

यदि आप वैकल्पिक पैरामीटर के साथ एक मैक्रो चाहते हैं जो आप कर सकते हैं:

//macro selection(vc++)
#define SELMACRO_IMPL(_1,_2,_3, N,...) N
#define SELMACRO_IMPL_(tuple) SELMACRO_IMPL tuple
#define mymacro1(var1) var1
#define mymacro2(var1,var2) var2*var1
#define mymacro3(var1,var2,var3) var1*var2*var3
#define mymacro(...) SELMACRO_IMPL_((__VA_ARGS__, mymacro3(__VA_ARGS__), mymacro2(__VA_ARGS__), mymacro1(__VA_ARGS__))) 

कि मेरे लिए vc में aswell काम किया। लेकिन यह शून्य मापदंडों के लिए काम नहीं करता है।

int x=99;
x=mymacro(2);//2
x=mymacro(2,2);//4
x=mymacro(2,2,2);//8

मैं मिल रहा हूँunresolved external symbol _bool referenced in function _main
अविवाहित बोरिसोव

हाँ कुछ मामलों में ऐसा हो सकता है। आपको उस बूल (#__ VA_ARGS__) के बारे में पता होना चाहिए? अन्य मैक्रोज़ से अलग है क्योंकि इसका मूल्यांकन रन टाइम पर किया जा रहा है। आपके मामले के आधार पर आप कोड के उस हिस्से को छोड़ सकते हैं।
Syphorlate

2
मैं वास्तव में pastebin.com/H3T75dcn के साथ समाप्त हुआ जो पूरी तरह से काम करता है (0 तर्क भी)।
अविद्या बोरिसोव

लिंक के लिए धन्यवाद, और हाँ आप इसे साइज़ोफ़ का उपयोग करके भी कर सकते हैं, लेकिन मेरे लिए जो कुछ मामलों में काम नहीं आया लेकिन सिद्धांत एक ही है (बूलियन मूल्यांकन)।
सिरफोरेट

क्या आप कुछ उदाहरण दे सकते हैं जहां यह विफल हो जाता है?
अविद्या बोरिसोव

7

gcc/ varargs macrosg++ का समर्थन करता है, लेकिन मुझे नहीं लगता कि यह मानक है, इसलिए इसे अपने जोखिम पर उपयोग करें।


4
वे C99 में मानक हैं, और उन्हें C ++ 0x में भी जोड़ा जा रहा है।
ग्रेफेड

5
#include <stdio.h>

#define PP_NARG(...) \
    PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) \
    PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N( \
    _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ 
    _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
    _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
    _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
    _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
    _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
    _61,_62,_63,N,...) N
#define PP_RSEQ_N() \
    63,62,61,60,                   \
    59,58,57,56,55,54,53,52,51,50, \
    49,48,47,46,45,44,43,42,41,40, \
    39,38,37,36,35,34,33,32,31,30, \
    29,28,27,26,25,24,23,22,21,20, \
    19,18,17,16,15,14,13,12,11,10, \
    9,8,7,6,5,4,3,2,1,0

#define PP_CONCAT(a,b) PP_CONCAT_(a,b)
#define PP_CONCAT_(a,b) a ## b

#define THINK(...) PP_CONCAT(THINK_, PP_NARG(__VA_ARGS__))(__VA_ARGS__)
#define THINK_0() THINK_1("sector zz9 plural z alpha")
#define THINK_1(location) THINK_2(location, 42)
#define THINK_2(location,answer) THINK_3(location, answer, "deep thought")
#define THINK_3(location,answer,computer) \
  printf ("The answer is %d. This was calculated by %s, and a computer to figure out what this"
          " actually means will be build in %s\n", (answer), (computer), (location))

int
main (int argc, char *argv[])
{
  THINK (); /* On compilers other than GCC you have to call with least one non-default argument */
}

अस्वीकरण: ज्यादातर हानिरहित।


आपके कोड में कोई त्रुटि है। कृपया करें :%s/MY_MACRO_/THINK_/g:)
जोओ पोर्टेला

यह भी, यह जी + i686-apple-darwin10-g++-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5664)
एच

1
शून्य मैक्रो के लिए शून्य तर्क मौजूद नहीं हैं, क्योंकि खाली टोकन एक मान्य प्लेसहोल्डर है।
पॉल फुल्ट्ज II

3

यह वास्तव में नहीं है जो प्रीप्रोसेसर के लिए डिज़ाइन किया गया है।

कहा कि, यदि आप पठनीयता के एक मोडिक के साथ गंभीरता से चुनौतीपूर्ण मैक्रो प्रोग्रामिंग के क्षेत्र में प्रवेश करना चाहते हैं, तो आपको बूस्ट प्रीप्रोसेसर लाइब्रेरी पर एक नज़र डालनी चाहिए । आखिरकार, यह C ++ नहीं होगा अगर प्रोग्रामिंग के तीन पूरी तरह से अनुकूल संगत स्तर (प्रीप्रोसेसर, टेम्पलेट मेटाप्रोग्रामिंग और बेस लेवल C ++) नहीं थे!


3
#define MY_MACRO_3(X,Y,Z) ...
#define MY_MACRO_2(X,Y) MY_MACRO(X,Y,5)
#define MY_MACRO_1(X) MY_MACRO(X,42,5)

आप कॉल के बिंदु पर जानते हैं कि आप कितने args पास करने जा रहे हैं ताकि वास्तव में ओवरलोडिंग की कोई आवश्यकता न हो।


2
मैं वास्तव में फीचर के अस्तित्व के बारे में पूछ रहा था।
सेनोक

3

डेरेक लेडबिटर कोड का अधिक संक्षिप्त संस्करण:

enum
{
    plain = 0,
    bold = 1,
    italic = 2
};


void PrintString(const char* message = NULL, int size = 0, int style = 0)
{
}


#define PRINT_STRING(...) PrintString(__VA_ARGS__)


int main(int argc, char * const argv[])
{ 
    PRINT_STRING("Hello, World!");
    PRINT_STRING("Hello, World!", 18);
    PRINT_STRING("Hello, World!", 18, bold);

    return 0;
}

3

भयानक मैक्रो राक्षसों के एक बड़े प्रशंसक के रूप में, मैं जेसन डेंग के जवाब पर विस्तार करना चाहता था और इसे वास्तव में प्रयोग करने योग्य बनाना था। (बेहतर या बदतर के लिए।) मूल का उपयोग करने के लिए बहुत अच्छा नहीं है क्योंकि आपको हर बार एक नया मैक्रो बनाने के लिए बड़े वर्णमाला सूप को संशोधित करने की आवश्यकता होती है और यदि आपको विभिन्न प्रकार के तर्कों की आवश्यकता होती है तो यह और भी बुरा है।

इसलिए मैंने इन सुविधाओं के साथ एक संस्करण बनाया:

  • 0 तर्क केस काम करता है
  • गन्दे भाग में बिना किसी संशोधन के १ से १६ तर्क
  • अधिक मैक्रो फ़ंक्शन लिखना आसान है
  • Gcc 10, clang 9, Visual Studio 2017 में परीक्षण किया गया

वर्तमान में मैंने सिर्फ 16 तर्क दिए हैं, लेकिन अगर आपको अधिक (वास्तव में अभी की जरूरत है? आप बस मूर्खतापूर्ण हो रहे हैं ...) आप FUNC_CHOOSER और CHOOSE_FROM_ARG_COUNT को संपादित कर सकते हैं, तो NOARG_EXPANDER में कुछ अल्पविराम जोड़ें।

कृपया कार्यान्वयन पर अधिक जानकारी के लिए जेसन देंग का उत्कृष्ट उत्तर देखें, लेकिन मैं यहां सिर्फ कोड डालूंगा:

#include <stdio.h>

void realCreate(int x, int y)
{
    printf("(%d, %d)\n", x, y);
}

// This part you put in some library header:
#define FUNC_CHOOSER(_f0, _f1, _f2, _f3, _f4, _f5, _f6, _f7, _f8, _f9, _f10, _f11, _f12, _f13, _f14, _f15, _f16, ...) _f16
#define FUNC_RECOMPOSER(argsWithParentheses) FUNC_CHOOSER argsWithParentheses
#define CHOOSE_FROM_ARG_COUNT(F, ...) FUNC_RECOMPOSER((__VA_ARGS__, \
            F##_16, F##_15, F##_14, F##_13, F##_12, F##_11, F##_10, F##_9, F##_8,\
            F##_7, F##_6, F##_5, F##_4, F##_3, F##_2, F##_1, ))
#define NO_ARG_EXPANDER(FUNC) ,,,,,,,,,,,,,,,,FUNC ## _0
#define MACRO_CHOOSER(FUNC, ...) CHOOSE_FROM_ARG_COUNT(FUNC, NO_ARG_EXPANDER __VA_ARGS__ (FUNC))
#define MULTI_MACRO(FUNC, ...) MACRO_CHOOSER(FUNC, __VA_ARGS__)(__VA_ARGS__)

// When you need to make a macro with default arguments, use this:
#define create(...) MULTI_MACRO(CREATE, __VA_ARGS__)
#define CREATE_0() CREATE_1(0)
#define CREATE_1(x) CREATE_2(x, 0)
#define CREATE_2(x, y) \
    do { \
        /* put whatever code you want in the last macro */ \
        realCreate(x, y); \
    } while(0)


int main()
{
    create();
    create(10);
    create(20, 20);
    //create(30, 30, 30);  // Compilation error
    return 0;
}

2

आप BOOST_PP_OVERLOADएक boostपुस्तकालय से उपयोग कर सकते हैं ।

आधिकारिक बूस्ट डॉक से उदाहरण :

#include <boost/preprocessor/facilities/overload.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/facilities/empty.hpp>
#include <boost/preprocessor/arithmetic/add.hpp>

#define MACRO_1(number) MACRO_2(number,10)
#define MACRO_2(number1,number2) BOOST_PP_ADD(number1,number2)

#if !BOOST_PP_VARIADICS_MSVC

#define MACRO_ADD_NUMBERS(...) BOOST_PP_OVERLOAD(MACRO_,__VA_ARGS__)(__VA_ARGS__)

#else

// or for Visual C++

#define MACRO_ADD_NUMBERS(...) \
  BOOST_PP_CAT(BOOST_PP_OVERLOAD(MACRO_,__VA_ARGS__)(__VA_ARGS__),BOOST_PP_EMPTY())

#endif

MACRO_ADD_NUMBERS(5) // output is 15
MACRO_ADD_NUMBERS(3,6) // output is 9

0

आपको जो चाहिए, उसके आधार पर, आप इसे मैक्रोज़ के साथ var args के साथ कर सकते हैं। अब, वैकल्पिक पैरामीटर या मैक्रो ओवरलोडिंग, ऐसी कोई बात नहीं है।


-1

उपरोक्त उदाहरणों में से कोई भी (डेरेक लेडबेटेर, डेविड सोरकोवस्की और जो डी से) मैक्रों के साथ तर्क गिनने के लिए मेरे लिए माइक्रोसॉफ्ट वीसीसी 10 का उपयोग करके काम किया गया। इस __VA_ARGS__तर्क को हमेशा एक ही तर्क के रूप में माना जाता है (टोकन-इसे साथ लेना ##या नहीं), इसलिए वह तर्क शिफ्टिंग जिसमें उन उदाहरणों पर भरोसा किया जाता है वह काम नहीं करता है।

इसलिए, संक्षिप्त उत्तर, जैसा कि ऊपर कई अन्य लोगों द्वारा कहा गया है: नहीं, आप मैक्रोज़ को अधिभार नहीं दे सकते हैं या उन पर वैकल्पिक तर्क का उपयोग नहीं कर सकते हैं।


1
आप कर सकते हैं, लेकिन केवल C99 या C ++ 11 में (__VA_ARGS__ होने के कारण)। VC2010 C89 / C ++ 03 है (C ++ 11 के कुछ बिट्स को चालू करना है, लेकिन अभी तक ऐसा नहीं है)।
puetzk
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.