2012-02-07 18 views
21

तो मुझे एक मैक्रो मिला है जो जीसीसी में अच्छी तरह से काम करता है, लेकिन माइक्रोसॉफ्ट के सी ++ कंपाइलर में नहीं। मुझे उम्मीद है कि किसी को कामकाज के बारे में पता हो सकता है, या शायद मुझे समझा सकता है कि यह इस तरह से क्यों व्यवहार करता है।एमएसवीसी ++ वैरैडिक मैक्रो विस्तार

मुझे यकीन है कि यह मैक्रो बिल्कुल "मानक" नहीं है, लेकिन यह वास्तव में मेरी मदद करेगा।

यहाँ मैक्रो का एक कार्यात्मक उदाहरण है:

struct MyStructure 
{ 
    void Foo() 
    { 
    EXPAND_THESE(Property1, Property2, Property3, Property4) 
    } 

    Base * parent; 
} 

यहां बताया गया है जीसीसी ऊपर का विस्तार:

#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N 
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1) 

#define FULLY_EXPANDED(count, ...) \ 
    MAC## count (__VA_ARGS__) 

#define SEMI_EXPANDED(count, ...) FULLY_EXPANDED(count, __VA_ARGS__) 

#define EXPAND_THESE(...) SEMI_EXPANDED(VA_NARGS(__VA_ARGS__), __VA_ARGS__) 

#define ACTUAL_MACRO(x) parent->GetProperty<x>(); 
#define MAC1(a) ACTUAL_MACRO(a) 
#define MAC2(a,b) MAC1(a) ACTUAL_MACRO(b) 
#define MAC3(a,b,c) MAC2(a,b) ACTUAL_MACRO(c) 
#define MAC4(a,b,c,d) MAC3(a,b,c) ACTUAL_MACRO(d) 
#define MAC5(a,b,c,d,e) MAC4(a,b,c,d) ACTUAL_MACRO(e) 

यहाँ कैसे मैं इस मैक्रो का उपयोग कर सकते है

struct MyStructure 
{ 
    void Foo() 
    { 
    parent->GetProperty<Property1>(); 
    parent->GetProperty<Property2>(); 
    parent->GetProperty<Property3>(); 
    parent->GetProperty<Property4>(); 
    } 

    Base * parent; 
} 

लेकिन किसी कारण से माइक्रोसॉफ्ट मेरे सभी __VA_ARGS__ को एक तर्क के रूप में फैलाता है:

struct MyStructure 
{ 
    void Foo() 
    { 
    parent->GetProperty<Property1, Property2, Property3, Property4>(); 
    } 

    Base * parent; 
} 

क्या कोई जानता है कि यह क्यों है? क्या माइक्रोसॉफ्ट को जीसीसी की तरह विस्तारित करने के लिए मैं कुछ चाल खींच सकता हूं? शायद कोष्ठक के कुछ अतिरिक्त जोड़े में टॉस?

इस तरह के मैक्रोज़ वास्तव में मुझे "गोंद" कोड का एक गुच्छा बदलने में मदद कर सकते हैं, लेकिन इस समस्या के कारण, मैं इसे अपने वीएस प्रोजेक्ट में नहीं ले जा सकता। किसी भी तरह की सहायता का स्वागत किया जाएगा!

धन्यवाद।

+5

'सा [बग] (http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement) और मुझे नहीं लगता कि वे जल्द ही इसे ठीक करने की योजना बनाते हैं। –

+0

लिंक्ड डुप्लिकेट: [एमएसवीसी ++ (माइक्रोसॉफ्ट विजुअल स्टूडियो) में "मैक्रो ओवरलोडिंग" के साथ वैरैडिक मैक्रो से जुड़े मुद्दों को कैसे ठीक करें?] (Https://stackoverflow.com/q/48710758/514235) - @ जेसेगूड थक्स को इंगित करने के लिए बग। – iammilind

उत्तर

17

संयोग से, मैं आज इस समस्या में भाग गया, और पर्याप्त प्रयास के बाद मुझे लगता है कि मुझे अपने उद्देश्यों के लिए समाधान मिला है। बग एमएसवीसी __VA_ARGS__ तर्क सूची में एक टोकन के रूप में व्यवहार करता है। लेकिन आप सीधे मैक्रो कॉल तर्क सूची में इसका उपयोग न करके इसका काम कर सकते हैं। This comment अपनी समस्याओं का जवाब की शुरुआत पता चलता है:

#define VA_NARGS(...) VA_NUM_ARGS_IMPL_((__VA_ARGS__, 5,4,3,2,1)) 
#define VA_NARGS_IMPL_(tuple) VA_NUM_ARGS_IMPL tuple 
#define VA_NARGS_IMPL(_1,_2,_3,_4,_5,N,...) N 

लेकिन फिर मुझे लगता है आप की संभावना सुनिश्चित करने के मुद्दे कि पूरी तरह से वास्तविक "एन" आप चाहते हैं करने के लिए विस्तारित हो जाता है में चलाने देंगे, और VA_NARGS_IMPL (arg1, arg2, 5, 4, 3, 2, 1) के लिए नहीं कहो। मैंने पाया कि मेरा कोड (जो आपके जैसा दिखता था) को MAC##code को एक इकाई के रूप में विस्तारित करने के लिए बदलना पड़ा था, और उसके बाद इसे तर्क सूची के साथ अलग से जोड़ा जाना था। यहाँ कोड है कि मैं मेरे लिए काम किया पाया है:

#define ASSERT_HELPER1(expr) singleArgumentExpansion(expr) 
#define ASSERT_HELPER2(expr, explain) \ 
    twoArgumentExpansion(expr, explain) 

/* 
* Count the number of arguments passed to ASSERT, very carefully 
* tiptoeing around an MSVC bug where it improperly expands __VA_ARGS__ as a 
* single token in argument lists. See these URLs for details: 
* 
* http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement 
* http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/#comment-644 
*/ 
#define COUNT_ASSERT_ARGS_IMPL2(_1, _2, count, ...) \ 
    count 
#define COUNT_ASSERT_ARGS_IMPL(args) \ 
    COUNT_ASSERT_ARGS_IMPL2 args 
#define COUNT_ASSERT_ARGS(...) \ 
    COUNT_ASSERT_ARGS_IMPL((__VA_ARGS__, 2, 1, 0)) 
/* Pick the right helper macro to invoke. */ 
#define ASSERT_CHOOSE_HELPER2(count) ASSERT_HELPER##count 
#define ASSERT_CHOOSE_HELPER1(count) ASSERT_CHOOSE_HELPER2(count) 
#define ASSERT_CHOOSE_HELPER(count) ASSERT_CHOOSE_HELPER1(count) 
/* The actual macro. */ 
#define ASSERT_GLUE(x, y) x y 
#define ASSERT(...) \ 
    ASSERT_GLUE(ASSERT_CHOOSE_HELPER(COUNT_ASSERT_ARGS(__VA_ARGS__)), \ 
       (__VA_ARGS__)) 

int foo() 
{ 
    ASSERT(one); // singleArgumentExpansion(one) 
    ASSERT(two, "foopy"); // twoArgumentExpansion(two, "foopy") 
} 

मेरा मन कुछ ही घंटों के अपने ही मुद्दों को सुलझाने तो जाने के लिए और पूरी तरह से हल तुम्हारा करने के बाद बहुत ज्यादा गूदा है, मैं कहना है माफी चाहता हूँ। :-) लेकिन मुझे लगता है कि यह आपको कुछ काम करने के लिए पर्याप्त है, जो थोड़ा काम करता है।

16

मुझे पता है कि यह प्रश्न दो साल से अधिक पुराना है, लेकिन मैंने सोचा कि मैं उन लोगों के लिए अधिक पॉलिश जवाब देने का प्रयास करूंगा जो अभी भी इस पर ठोकर खाएंगे।

जेफ वाल्डन का उत्तर काम करता है और सब कुछ, लेकिन आपको प्रत्येक खाद्य मैक्रो के लिए FOO_CHOOSE_HELPER/1/2 घोषित करना है, जिसमें आप विविध तर्क चाहते हैं। मैंने इस मुद्दे को हल करने के लिए अमूर्तता की एक परत विकसित की है।

#define GLUE(x, y) x y 

#define RETURN_ARG_COUNT(_1_, _2_, _3_, _4_, _5_, count, ...) count 
#define EXPAND_ARGS(args) RETURN_ARG_COUNT args 
#define COUNT_ARGS_MAX5(...) EXPAND_ARGS((__VA_ARGS__, 5, 4, 3, 2, 1, 0)) 

#define OVERLOAD_MACRO2(name, count) name##count 
#define OVERLOAD_MACRO1(name, count) OVERLOAD_MACRO2(name, count) 
#define OVERLOAD_MACRO(name, count) OVERLOAD_MACRO1(name, count) 

#define CALL_OVERLOAD(name, ...) GLUE(OVERLOAD_MACRO(name, COUNT_ARGS_MAX5(__VA_ARGS__)), (__VA_ARGS__)) 
इस वास्तुकला के साथ

आप इस तरह के रूप variadic मैक्रो भी निर्धारित कर सकते हैं:: निम्नलिखित पर विचार करें

#define ERROR1(title) printf("Error: %s\n", title) 
#define ERROR2(title, message)\ 
    ERROR1(title);\ 
    printf("Message: %s\n", message) 

#define ERROR_CHOOSE_HELPER2(count) ERROR##count 
#define ERROR_CHOOSE_HELPER1(count) ERROR_CHOOSE_HELPER2(count) 
#define ERROR_CHOOSE_HELPER(count) ERROR_CHOOSE_HELPER1(count) 

#define ERROR(...) GLUE(ERROR_CHOOSE_HELPER(COUNT_ARGS_MAX5(__VA_ARGS__)),\ 
    (__VA_ARGS__)) 

#define ASSERT1(expr) singleArgumentExpansion(expr) 
#define ASSERT2(expr, explain) twoArgumentExpansion(expr, explain) 

#define ASSERT_CHOOSE_HELPER2(count) ASSERT##count 
#define ASSERT_CHOOSE_HELPER1(count) ASSERT_CHOOSE_HELPER2(count) 
#define ASSERT_CHOOSE_HELPER(count) ASSERT_CHOOSE_HELPER1(count) 

#define ASSERT(...) GLUE(ASSERT_CHOOSE_HELPER(COUNT_ARGS_MAX5(__VA_ARGS__)),\ 
    (__VA_ARGS__)) 

यह है: जेफ के जवाब के साथ

#define ERROR1(title) printf("Error: %s\n", title) 
#define ERROR2(title, message)\ 
    ERROR1(title);\ 
    printf("Message: %s\n", message) 
#define ERROR(...) CALL_OVERLOAD(ERROR, __VA_ARGS__) 

#define ASSERT1(expr) singleArgumentExpansion(expr) 
#define ASSERT2(expr, explain) twoArgumentExpansion(expr, explain) 
#define ASSERT(...) CALL_OVERLOAD(ASSERT, __VA_ARGS__) 

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

उदाहरण उपयोग:

int foo() 
{ 
    ASSERT(one); // singleArgumentExpansion(one) 
    ASSERT(two, "foopy"); // twoArgumentExpansion(two, "foopy") 

    ERROR("Only print a title"); 
    ERROR("Error title", "Extended error description"); 
} 
+0

नोट, मुझे ';' को हटाने की आवश्यकता है '# परिभाषित करें CALL_OVERLOAD' के अंत में या मुझे एक त्रुटि 'त्रुटि: अपेक्षित') 'पहले'; ' gcc4.9 – ideasman42

+0

के साथ टोकन' इस पर आधारित एक उदाहरण है जो एक var-args आधारित ELEM मैक्रो लागू करने के लिए 16 तर्कों का उपयोग करता है, http://stackoverflow.com/a/24837037/432509 (ब्याज का हो सकता है) – ideasman42

+0

@ ideasman42 इसे इंगित करने के लिए धन्यवाद, इसे अपडेट किया गया। –

संबंधित मुद्दे