سؤال

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

يجب أن تتوسع إلى:

std::ostringstream oss;
oss << 1 << "hello world" << blah->getValue() << std::endl;
ThreadSafeLogging(oss.str());
هل كانت مفيدة؟

المحلول

#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.

عندما ينتهي البيان (أي مباشرة بعد الانتقائية في عملية الطباعة بأكملها في Main ()) ، فإن الكائن المؤقت يخرج من النطاق ويتم تدميره. ال my_stream مكالمات المدمرة ThreadSafeLogging مع البيانات "التي تم جمعها" سابقا.

تم اختباره (G ++).

شكرا/ائتمانات ل دينغو للإشارة إلى كيفية تبسيط الأمر برمته ، لذلك لا أحتاج إلى التحميل الزائد operator<<. لا يمكن مشاركة عمليات الصعود السيئة للغاية.

نصائح أخرى

ألا يمكنك فقط أن تستمد من Ostream وتوفير تنفيذ آمن لخيطك الخاص؟ ثم يمكنك القيام فقط

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

والحصول على نفس الوظيفة بالضبط بدون وحدات الماكرو واستخدام C ++ بشكل صحيح؟

لا. المشكلة هي أنه بدون استخدام بناء جملة الوظيفة ، يقتصر الماكرو على استبداله فقط.

ولكن إذا كنت على استعداد لاستخدام بناء جملة الوظيفة ، فيمكنك استبدال الأشياء قبل وبعد Args.

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

يمكنك من خلال تعريف mymacro على النحو التالي:

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

ألق نظرة على google-glog, ، يفعلون ذلك باستخدام كائن مؤقت مستند إلى أ

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

ولديهم أيضًا وحدات ماكرو أخرى مثيرة للاهتمام مثل log_if et al.

بالنظر إلى أن لديك هذه الخطوط مدرجة في مكان ما في الكود الخاص بك ، نعم هذا ممكن

#include <iostream>
#include <sstream> 

__LINE__ يتم تعريف الماكرو من قبل جميع المترجمين Standart. حتى نتمكن من استخدامه لإنشاء اسم متغير يختلف في كل مرة تستخدم فيها الماكرو :)

فيما يلي نسخة جديدة يُنظر إليها على أنها تعليمات منظمة واحدة فقط: (تم تحريرها)

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

// So you can use it like this 
int main() 
{ 
    if (4 != 2)
        my_macro << 4 << " hello "  << std::endl; 
    my_macro << 2 << " world !" << std::endl; 
} 

ربما لن يحتاج التطوير إلى استخدام هذا الماكرو مرتين على نفس الخط لأن بساطة المشغل <<. ولكن في حال كنت بحاجة إلى ذلك ، يمكنك تبديل استخدام __LINE__ بواسطة __COUNTER__ (وهو غير قياسي!). بفضل Quuxplusone لهذه النصيحة

هذه خدعة سيئة أخرى رأيتها في مكان آخر. له عيب كبير مقارنة بإجابتي الأخرى: لا يمكنك استخدامه مرتين في نفس النطاق لأنه يعلن عن متغير. ومع ذلك ، قد لا يزال من المثير للاهتمام آخر الحالات التي تريد أن يكون فيها somemacro foo قم بتشغيل شيء ما بعد foo.

#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;
}

إعداد التسجيل لدي مشابه تمامًا:

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 أبدًا ولم يكن هناك القليل من النفقات العامة. يمكنك تكوين التسجيل على اسم الملف وأرقام السطر أو مستويات الأولوية. يمكن أن تتغير وظيفة يجب أن تتغير بين الدعوات ، بحيث يمكنك خنق أو الحد من الإخراج. يستخدم إخراج السجل وظيفتين لتعديل نفسه ، البادئة التي تضيف "ملف: السطر: (PRIO)" إلى السطر ، و Flush () التي تنطلق إلى إخراج السجل كأمر واحد ويضيف خطًا جديدًا إليه . في تنفيذي يحدث دائمًا ، ولكن يمكنك جعل ذلك مشروطًا إذا لم يكن هناك بالفعل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top