2010-08-16 34 views
5

मैं C++ में लॉग क्लास लिख रहा हूं। यह वर्ग एक सिंगलटन है। मैं इस तरह से लॉग जोड़ना चाहते हैं:ऑपरेटर << - अंतिम तर्क का पता कैसे लगाएं

Log::GetInstance() << "Error: " << err_code << ", in class foo"; 

ठीक है, और एक लॉग ऑब्जेक्ट के अंदर, मैं समय पर इस पूरे लाइन को बचाने के लिए जब अंतिम तर्क इस उदाहरण में आता है (", वर्ग foo में" चाहते हैं)।

अंतिम एक < < तर्क का पता कैसे लगाएं? < < एक < < ख < < < is_this_last < maybe_this_is < < or_not।

मुझे किसी भी अंत टैग का उपयोग नहीं करना है।

+1

मुझे लगता है कि ओवरलोडिंग ऑपरेटर << वह है जो आप यहां चाहते हैं – Falmarri

+1

@Falmarri: मुझे वास्तव में यह दृष्टिकोण पसंद है। यह क्यूटी अपने 'क्यूडीबग' वर्ग का उपयोग कैसे करता है। – Job

+1

और क्यूटी भाषा के खिलाफ काम कर रहा है। सिर्फ इसलिए कि उनका मतलब यह नहीं हो सकता कि उन्हें चाहिए। –

उत्तर

17

आप सिंगलटन का उपयोग न करके इस समस्या को हल कर सकते हैं। आप इस तरह से एक समारोह करते हैं:

Log log() 
{ 
    return Log(); 
} 

आप एक लॉग लगभग उसी तरह तुमने जोड़ सकते हैं इससे पहले कि:

log() << "Error: " << err_code << ", in class foo"; 

अंतर यह है कि है Log वस्तु का नाशक इस लाइन के बाद कहा जाता हो जाता है । तो अब आपके पास यह पता लगाने का एक तरीका है कि अंतिम तर्क संसाधित होने पर।

+0

कुछ ऑब्जेक्ट को अभी भी खुले फ़ाइल हैंडल को बनाए रखना है ... – Potatoswatter

+0

@Potatoswatter: हाँ। चूंकि वह एक सिंगलटन का उपयोग कर रहा था, इसलिए मैं इसे 'लॉग' कक्षा का स्थिर सदस्य बनाउंगा। अन्य समाधान निश्चित रूप से संभव हैं। – Job

+0

मुझे कन्वेयर और विनाशक के साथ खेलने वाली आरएआईआई तकनीक पसंद है, मुझे लगता है कि यह वास्तव में सुरुचिपूर्ण है। –

9

मैं आपके Log::GetInstance लॉग ऑब्जेक्ट के बजाय प्रॉक्सी ऑब्जेक्ट वापस कर दूंगा। प्रॉक्सी ऑब्जेक्ट उस डेटा को सहेज लेगा जो इसे लिखा गया है, और उसके बाद इसके विनाशक में, यह वास्तव में लॉग में संचित डेटा लिख ​​देगा।

+0

+1: हालांकि सिंगलेट्स बदसूरत हो सकते हैं, सलाह देना बेहतर है जिसके लिए कम अनावश्यक रिफैक्टरिंग की आवश्यकता होती है। – Potatoswatter

1

अपने ऑपरेटरों के साथ बहुत चालाक न हों। जब आप ऐसा करने के लिए समझ में आता है तो आपको ऑपरेटरों को ओवरलोड करना चाहिए। यहां आपको नहीं करना चाहिए। यह अजीब लग रहा है।

Log::Message(message_here); 

जो एक std :: स्ट्रिंग लेता है:

तुम सिर्फ एक स्थिर विधि है कि इस तरह दिखता है होना चाहिए। फिर ग्राहकों को त्रुटि स्ट्रिंग को इकट्ठा करने के बारे में पता लगाने का सिर दर्द होता है।

+4

यह अजीब क्यों है? सी ++ धाराएं वैसे ही काम करती हैं। – Job

+0

@ जॉब: नहीं, सी ++ धाराएं नहीं हैं। विशेष रूप से, वे अंतिम आमंत्रण में कुछ खास नहीं करते हैं। एक सी ++ स्ट्रीम ऑब्जेक्ट एक तर्क के फ़ंक्शन को चलाने के लिए 'ऑपरेटर <<() 'का उपयोग करता है, और एक C++ स्ट्रीम ऑब्जेक्ट देता है जो फिर से फ़ंक्शन चला सकता है। ऑपरेटर ओवरलोडिंग साफ है, लेकिन यह बहुत लचीला या विस्तार योग्य नहीं है, और ऐसे मामले हैं जहां एक और आवश्यकता जोड़ने से ऑपरेटर खराब विचार को ओवरलोड कर देता है। –

+0

@ डेविड: लेकिन जवाब 'ऑपरेटर <<' के बारे में बात नहीं कर रहा है, जो कि पहले ऑपरेटर << 'कर रहा है, अजीब है। जो यह नहीं है – GManNickG

4

ऑपरेटर < < के बाद आप लॉग को एक अलग ऑब्जेक्ट करते हैं।

template<typename T> 
LogFindT operator<<(Log aLog, T const& data) 
{ 
    // Put stuff in log. 
    log.putStuffInLog(data); 

    // now return the object to detect the end of the statement. 
    return LogFindT(aLog); 
} 


struct LogFindT 
{ 
    LogFindT(Log& aLog) : TheLog(aLog) {} 
    Log& TheLog; 
    ~LogFindT() 
    { 
     // Do stuff when this object is eventually destroyed 
     // at the end of the expression. 
    } 
}; 

template<typename T> 
LogFindT& operator<<(LogFindT& aLog, T const& data) 
{ 
    aLog.TheLog.putStuffInLog(data); 

    // Return a reference to the input so we can chain. 
    // The object is thus not destroyed until the end of the stream. 
    return aLog; 
} 
4

मुझे लगता है कि जैरी और मार्टिन सबसे अच्छा सुझाव दे दिया है, लेकिन पूर्णता के लिए के लिए, पहली बात मैं के बारे में सोचा std::endl था।

आप एक कस्टम streambuf वर्ग द्वारा iostream प्रणाली के भीतर Log लागू किया है, तो आप बस पंक्ति के अंत में << endl या << flush जोड़ सकते हैं। चूंकि आप पूछ रहे हैं, मुझे लगता है कि आपने नहीं किया।

लेकिन आप endl कामों की नकल कर सकते हैं।या तो एक जोड़तोड़ हैंडलर

Log &operator<< (Log &l, Log & (*manip)(Log &)) 
    { return manip(l); } // generically call any manipulator 

Log &flog(Log &l) // define a manipulator "flush log" 
    { l->flush(); return l; } 

जोड़ सकते हैं या एक समर्पित operator<<

struct Flog {} flog; 

Log &operator<< (Log &l, Flog) 
    { l->flush(); return l; } 
0

वहाँ आप क्या चाहते हैं करने के लिए कोई अच्छा तरीका है जोड़ें। सी और सी ++ लाइन-उन्मुख भाषाओं नहीं हैं। "कोड की रेखा" या कुछ भी जैसी कोई बड़ी इकाई नहीं है, न ही किसी भी तरह से जंजीर कॉल संयुक्त हैं।

C++ में अभिव्यक्ति "एक < < ख < < ग < < घ" वास्तव में ऑपरेटर < < को तीन अलग-अलग कॉल के बराबर है, इस तरह:

t1 = a; 
t2 = t1.operator<<(b); 
t3 = t2.operator<<(c); 
t4 = t3.operator<<(d); 

क्यों सी ++ ostreams उपयोग endl है कि एक के रूप में स्पष्ट अंत-रेखा मार्कर; अन्यथा ऐसा करने का कोई अच्छा तरीका नहीं है।

+0

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

+2

तो मूल रूप से उन्हें सिखाने की बजाए आप कहते हैं, "आप इसे समझ नहीं पाएंगे, कोशिश न करें।" साथ ही, इन प्रॉक्सी को पिछले दशक में किए गए किसी भी कंपाइलर द्वारा पूरी तरह से रेखांकित किया जाएगा, कोई ओवरहेड नहीं है। यहां तक ​​कि अगर वहां एक साफ इंटरफेस तेज से बेहतर है। (कोई हमेशा एक प्रोफाइलर * (अनुमान लगाने वाला नहीं) के साथ एक साफ इंटरफ़ेस बना सकता है, लेकिन एक तेज़ इंटरफ़ेस साफ करने के लिए बहुत कठिन है।) – GManNickG

+1

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

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