2010-02-03 11 views
20
my_macro << 1 << "hello world" << blah->getValue() << std::endl; 

का विस्तार करना चाहिए में:क्या सी ++ मैक्रो के रूप में निम्नलिखित लिखने के लिए वैसे भी है?

std::ostringstream oss; 
oss << 1 << "hello world" << blah->getValue() << std::endl; 
ThreadSafeLogging(oss.str()); 
+0

मुझे आश्चर्य है कि आप #define my_macro (blah) {std :: ostringstream oss कर सकते हैं; ओएसएस ब्लाह; ThreadSafeLogging (oss.str()); } –

+0

यह भी देखें: https://stackoverflow.com/questions/4446484/a-line-based-thread-safe-stdcerr-for-c –

उत्तर

72
#define my_macro my_stream() 
class my_stream: public std::ostringstream { 
public: 
    my_stream() {} 
    ~my_stream() { 
     ThreadSafeLogging(this->str()); 
    } 
}; 
int main() { 
    my_macro << 1 << "hello world" << std::endl; 
} 

प्रकार my_stream का एक अस्थायी बनाई गई है, जो ostringstream का एक उपवर्ग है। ostringstream पर उस अस्थायी कार्य के लिए सभी ऑपरेशन।

जब कथन समाप्त होता है (यानी मुख्य() में पूरे प्रिंटिंग ऑपरेशन पर अर्धविराम के ठीक बाद, अस्थायी वस्तु दायरे से बाहर हो जाती है और नष्ट हो जाती है। my_stream विनाशक पहले से एकत्रित डेटा के साथ ThreadSafeLogging पर कॉल करता है।

परीक्षण (जी ++)।

धन्यवाद/पूरी चीजों को सरल बनाने के तरीके को इंगित करने के लिए dingo पर क्रेडिट, इसलिए मुझे ओवरलोडेड operator<< की आवश्यकता नहीं है। बहुत खराब अपवॉट साझा नहीं किया जा सकता है।

+7

यह मेरे जीवन में देखा गया सी ++ विनाशकों का सबसे शानदार उपयोग (या दुरुपयोग) है। – anon

+0

नहीं, मैक्रो एक अस्थायी बनाता है, जो अस्थायी निष्पादन वाली रेखा के बाद नष्ट हो जाता है। –

+0

मैं अपने विनाशक चेतावनी वापस लेता हूं; यह अस्थायी बनने के कारण तुरंत नष्ट हो जाता है। अच्छी तरह से किया। – MikeSep

2

नहीं। समस्या यह है कि समारोह सिंटेक्स के उपयोग के बिना, कोई मैक्रो केवल प्रतिस्थापित किया जा रहा है, जहां यह है करने के लिए सीमित है।

लेकिन यदि आप फ़ंक्शन सिंटैक्स का उपयोग करने के इच्छुक थे, तो आप तर्कों के पहले और बाद में सामान को प्रतिस्थापित कर सकते हैं।

my_macro(1 << "hello world" << blah->getValue() << std::endl); 

आप कर सकते थे MyMacro के रूप में परिभाषित करते हुए:

#define my_macro(args) std::ostreamstring oss; \ 
         oss << args; \ 
         ThreadSafeLogging(oss.str()); 
+5

निकोलस के उत्तर को देखते हुए, ऐसा लगता है कि "नहीं" गलत है। –

3

क्या आप अभी ओस्ट्रीम से प्राप्त नहीं हो सकते हैं और अपना खुद का थ्रेड सुरक्षित कार्यान्वयन प्रदान नहीं कर सकते? तो फिर तुम सिर्फ कर सकता है

myCOutObject << 1 << "hello world" << blah->getValue() << std::endl; 

और मैक्रो के बिना ठीक उसी कार्यक्षमता प्राप्त और सी ठीक से उपयोग ++?

2

google-glog पर एक नजर डालें, वे इस एक

LOG(INFO) << "log whatever" << 1; 

साथ instanciated एक अस्थायी वस्तु का उपयोग करते हैं और वे भी इस तरह के LOG_IF एट अल के रूप में अन्य रोचक मैक्रो है।

1

यहां एक और बुरा चाल है जिसे मैंने कहीं और देखा था। मेरे दूसरे उत्तर की तुलना में इसका एक बड़ा नुकसान है: आप इसे एक ही दायरे में दो बार उपयोग नहीं कर सकते क्योंकि यह एक चर घोषित करता है। हालांकि, यह अन्य मामलों के लिए अभी भी दिलचस्प हो सकता है जहां आप somemacro foofoo के बाद कुछ चलाना चाहते हैं।

#define my_macro \ 
    std::ostringstream oss; \ 
    for (int x=0; x<2; ++x) \ 
     if (x==1) ThreadSafeLogging(oss.str()); \ 
     else oss 

int main() { 
    my_macro << 1 << "hello world" << std::endl; 
} 
2

बेशक आप इसे एक से अधिक बार उपयोग कर सकते हैं :)! __LINE__ मैक्रो सभी स्टैंडएट कंपाइलर्स द्वारा परिभाषित किया गया है। तो हम ostrinstream चर नाम उत्पन्न करने के लिए उपयोग कर सकते हैं :)

#define Var_(Name, Index) Name##Index 
#define Var(Name, Index) Var_(Name, Index) 
#define my_macro \ 
    std::ostringstream Var(oss, __LINE__);   \ 
for (int x=0; x<2; ++x) \ 
    if (x==1) std::cout << Var(oss, __LINE__).str(); \ 
    else Var(oss, __LINE__) 

ठीक ठीक नहीं दो बार एक ही लाइन पर, पी लेकिन .. जो कि क्या करना होगा !!?

int main() { 
    my_macro << 4 << " hello " << std::endl; 
    my_macro << 2 << " world !" << std::endl; 
} 
+0

इसे एक नाम क्यों दें, इस पर एक पिछली पोस्ट का मेरा जवाब देखें। आप ऑब्जेक्ट 'MyObject()' को एक अस्थायी के रूप में उपयोग कर सकते हैं और कथन के अंत में इसे नष्ट करने पर भरोसा कर सकते हैं। – dascandy

+0

चालाक! ध्यान दें कि सभी लोकप्रिय कंपाइलरों पर आप मानक '__LINE__' के बजाय गैर-मानक' __COUNTER__' का उपयोग कर सकते हैं और फिर यह उसी पंक्ति पर कई बार काम करेगा। हालांकि, किसी भी मामले में, यह मैक्रो स्वच्छ नहीं है; अगर आप कहते हैं कि 'अगर (लॉग) my_macro << 4 << std :: endl;' तो आपके पास एक बुरा समय होगा। Google-glog's LOG() विनाशक चाल के आधार पर शीर्ष-वोट वाला उत्तर, स्वच्छ है। – Quuxplusone

2

लॉगिंग सेटअप मैं काफी समान है: अपने लॉगिंग अक्षम है

bool ShouldLog(const char* file, size_t line, Priority prio); 

class LoggerOutput : public std::stringstream { 
public: 
    LoggerOutput(const char* file, size_t line, Priority prio) 
    : prio(prio) 
    { 
    Prefix(file, line, prio); 
    } 
    void Prefix(const char* file, size_t line, Priority prio); 
    ~LoggerOutput() { 
    Flush(); 
    } 
    void Flush(); 
private: 
    Priority prio; 
}; 

#define LOG(Prio) if (!Logging::ShouldLog(__FILE__, __LINE__, Prio)) {} else Logging::LoggerOutput(__FILE__, __LINE__, Prio) 

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

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