2010-09-02 10 views
9

से भिन्न होते हैं, मुझे यह लॉगिंग सिस्टम मिला है जिसके लिए मैं स्ट्रिंग मैनिपुलेशन में से कुछ को शॉर्टकट करना चाहता हूं।फंक्शन ओवरलोडिंग जहां पैरामीटर केवल इलिप्स

लॉगिंग सिस्टम का उपयोग कार्यात्मक मैक्रोज़ के माध्यम से किया जाता है जो उसके बाद एक फ़ंक्शन कॉल पर अग्रेषित होता है। जैसे #define Warning(...) LogMessage(eWarning, __VA_ARGS__);

लॉगमेसेज फिर snprintf को एक नए बफर में करता है और फिर उस संदेश को जो भी लॉग लक्ष्य स्थापित किया जाता है उसे प्रस्तुत करता है; printf, OutputDebugString, आदि

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

तो मेरे फ़ंक्शन प्रोटोटाइप को देखते हुए, क्या मुझे इलिप्स की उपस्थिति के आधार पर अधिभारित करने में सक्षम होना चाहिए? दूसरे शब्दों में, मुझे लगता है कि मैं की तरह कुछ कर सकते हैं सक्षम होना चाहिए:

LogMessage(LogLevel, const char* message, ...); 
LogMessage(LogLevel, const char* message); 

मेरे गूगल के प्रयास कुछ भी विशेष रूप से उपयोगी (बस मुझे दिखा रहा है कि दीर्घवृत्त अगर और कुछ नहीं करता है, से अलग से मेल खाएगी नहीं मिले मेरी आवश्यकताएं कुछ भी नहीं मैचों), और एक कार्यान्वयन पर मेरे प्रारंभिक स्टैब ने मुझे एक संदिग्ध फ़ंक्शन कॉल त्रुटि दी।

त्रुटि के साथ, मुझे बस यह स्वीकार करना चाहिए कि मैं ऐसा नहीं कर सकता, लेकिन मुझे आश्चर्य है कि यह केवल संकलक है जिसका उपयोग मैं कर रहा हूं या शायद मैं इसे गलत कर रहा हूं। मैं

// edited version of what I really have to remove our local APIs, 
// please excuse minor errors 
const char* message = NULL; 
char buffer[512]; 

va_list args; 
va_start(args, format); 

if(strcmp(format, "%s") == 0) { 
    message = va_arg(args, const char*); 
} 
else if (strchr(format, '%') == NULL) { 
    message = format; 
} 
else { 
    vsnprintf(buffer, 512, format, args); 
    message = buffer; 
} 

va_end(args); 

के साथ एक समान प्रभाव को प्राप्त कर सकते हैं ... लेकिन यह एक सामान्य मामला जो केवल मापदंडों पारित किया जा रहा की संख्या से जाना जा सकता है में बेकार लगता है। जैसे अगर इलिप्स कुछ भी मेल नहीं खाते हैं, तो अन्य फ़ंक्शन का चयन करें? यदि यह काम नहीं करता है, तो क्या कोई और तरीका है जिसे मैं कोशिश कर सकता हूं जिसके लिए उपयोगकर्ता को मैक्रो नाम से निर्णय लेने की आवश्यकता नहीं है जिसे फ़ंक्शन कहा जाएगा? ईमानदारी से यह "अपशिष्ट" के बारे में उतना ही नहीं है जब मुझे एहसास हुआ कि अगर किसी ने अपने लॉग संदेश में Error("Buffer not 100% full"); को खतरनाक रूप से कहा और परिणामस्वरूप "बफर 1007.732873e10ull" नहीं मिला।

संपादित करें: जबकि मेरे उदाहरण का उत्तर "ऐसा मत करो" द्वारा उत्तर दिया गया है, क्या प्रश्न का उत्तर ही दिया जा सकता है?

उत्तर

2

मैं यह करने के लिए मूल जवाब से प्रेरित था सवाल है, लेकिन मामूली सुधार के साथ आया है।

static void LogMessage(LogLevel level, const char* message); 

template <typename T> 
static void LogMessage(LogLevel level, const char* format, T t, ...) 
{ 
    LogMessageVA(level, format, (va_list)&t); 
} 

static void LogMessageVA(LogLevel level, const char* format, va_list argptr); 

यह 'मान लीजिए' के ​​बिना काम करता है कि दूसरा तर्क कॉन्स char * है।

3

मुझे यह भी एहसास हुआ कि आउटपुट संदेश में प्रतिशत प्रतीक होने पर यह विधि विफल हो जाएगी, क्योंकि स्नप्रिंट va_args को संसाधित करने का प्रयास करेगा।

फिर कॉलर सावधान रहें। यदि आपके फ़ंक्शन को printf-style प्रारूप स्ट्रिंग लेने के लिए प्रलेखित किया गया है तो यह किसी भी प्रतिशत संकेत से बचने के लिए कॉलर की ज़िम्मेदारी है। अवैध प्रारूप तारों को संभालने का प्रयास करने के लिए वास्तव में आपका काम नहीं है।

ईमानदारी से यह "बेकार" के बारे में के रूप में भी काफी नहीं है एक बार मैंने महसूस किया कि अगर किसी संयोग से उनके लॉग संदेश में Error("Buffer not 100% full"); कहा और मिल गया एक परिणाम के रूप में "बफर 1007.732873e10ull नहीं"।

मुझे लगता है कि आप से बेहतर कर रहे हैं सी ++ लोकाचार के साथ जा रहा है। जावा विधियों में आमतौर पर मान्य तर्कों की जांच करते हैं और अमान्य मानों को पारित करते समय अपवाद फेंक देते हैं। सी ++ में आप बस कॉलर्स को पैर में खुद को शूट करने देते हैं।उन्हें अपने काम को सही तरीके से कॉल करने के तरीके से सीखने के लिए हुप्स के माध्यम से कूदने के लिए 100%% लिखना बेहतर होता है।

+2

मुझे लगता है कि मुझे लगता है कि दर्शन नहीं खरीदते हैं, और मैं क्या स्वीकार में उदार मैं क्या भेजने में सतर्क रहना पसंद करते हैं। आईएमओ, अगर मैं उपयोगकर्ता के इरादे को दिव्य कर सकता हूं, तो मुझे चाहिए। अनुभवहीन प्रोग्रामर के कारण बस क्षेत्र में विफल होने वाला सॉफ़्टवेयर मेरे लिए अक्षम नहीं है। और मेरा मुद्दा स्पष्ट रूप से था कि मैं इन कार्यों को प्रिंटफ प्रारूप स्ट्रिंग्स * केवल * स्वीकार करने के रूप में दस्तावेज नहीं करना चाहता हूं, मैं चाहता हूं कि वे किसी भी तरह से जाएं। –

+0

जैसे ही आप की अनुमति देने के printf शैली तर्क, आप * चाहिए * मान जब आप उन्हें देखते हैं कि वे क्या कर रहे हैं, अन्यथा जो लोग उन्हें व्यवहार कि आप उम्मीद कर पाने के लिए नहीं जा रहे हैं का उपयोग करना चाहते है कि कि। यह प्रिंटफ-स्टाइल तर्कों को प्रिंटफ-स्टाइल तर्क के रूप में संसाधित करने की कोशिश करने और मिश्रण करने के लिए काम नहीं करेगा। यह सिर्फ परेशानी के लिए पूछ रहा है। यह जांचना ठीक है कि स्ट्रिंग स्प्रिंटफ के लिए मान्य है या नहीं, लेकिन प्रिंटफ-स्टाइल तर्कों को स्वीकार करने के लिए इसे साफ़ रूप से काम करने की अपेक्षा न करें और उन्हें एक ही समय में अनदेखा करें। –

+0

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

1

ठीक है मैं मैं प्रश्न के लिए एक समाधान के साथ आया लगता है।

तथ्य यह है कि आप ओवरलोड पर आधारित नहीं हो सकते हैं कि केवल इलिप्स के लिए पैरामीटर हैं या नहीं। अर्थात। आपके पास ऐसे कार्य नहीं हो सकते हैं जिनमें हस्ताक्षर हैं जो केवल अंडाकारों की उपस्थिति में भिन्न होते हैं।

हालांकि, यह अगर मैं दीर्घवृत्त प्रोटोटाइप से const char* पैरामीटर ड्रॉप मैं क्या पूछ रहा था की तरह कुछ करने के लिए संभव है। अर्थात।

LogMessage(LogLevel, ...); 
LogMessage(LogLevel, const char* message); 

स्पष्ट है, लेकिन अब आप सच है कि आप ग्रहण करने के लिए कि पहले पैरामीटर एक const char* है कि के साथ लड़ाई है, लेकिन यह अच्छी तरह से नहीं हो सकता। जॉन कुगलमैन की सलाह लेना, शायद यह ठीक है; आप उन पैरामीटर को दस्तावेज करते हैं जिन्हें अनुमति है और उपयोगकर्ता सावधान रहें। अगर वहाँ केवल एक const char* गैर दीर्घवृत्त फ़ंक्शन कॉल किया जाएगा, और अगर वहाँ दस्तावेज const char* कुछ पैरामीटर नंबर के बाद सहित किसी और किसी भी बात है दीर्घवृत्त समारोह बुलाया जाएगा।

दुर्भाग्य से ऐसा लगता है कि यह एक संभव समाधान vsnprintf करने के लिए मेरे उदाहरण मामले में, आप बच्चे के कार्यों के लिए पर va_args पारित करने के लिए अनुमति देता है की सीमा है।

यह शायद बुरा प्रपत्र मेरे अपने जवाब स्वीकार करने के लिए है, भले ही यह एक है कि प्रस्तुत सवाल का जवाब है।

1

C++ में 11 आप एकल तर्क मामले के लिए एक स्पष्ट विशेषज्ञता के साथ variadic टेम्पलेट का उपयोग कर सकते हैं:

void bar(int a, ...) { 
    // va_list stuff 
} 

template <typename... T> 
void foo(int a, T... args) { // (1) 
    bar(a, args...); // or do all the vararg stuff here directly 
} 

template <> 
void foo(int a) {   // (2) 
    printf("single\n"); 
} 

तब:

//foo(); // compile error, as expected 
foo(1);  // uses (2) 
foo(2,1); // uses (1) 
foo(3,1,"asdf"); // uses (1) 
...