هل هذا ممكن استخدام القطع الناقص في الماكرو؟هل يمكن تحويله إلى قالب؟

StackOverflow https://stackoverflow.com/questions/419559

سؤال

بعد أن قمت بتنفيذ CLogClass لإجراء تسجيل لائق، قمت أيضًا بتعريف الماكرو، ولكنه يعمل فقط مع معلمة واحدة ...

class CLogClass
{ 
public:
       static void DoLog(LPCTSTR sMessage, ...);
};
#define DebugLog(sMessage, x) ClogClass::DoLog(__FILE__, __LINE__, sMessage, x)

حسنًا، يفشل عند الاتصال بأكثر من معلمتين :( ...هل من الممكن تجنب ذلك على الإطلاق؟هل يمكن ترجمتها إلى قوالب بطريقة أو بأخرى؟

يحرر:تم تقديم وحدات الماكرو المتغيرة في VS 2005 (لكنني حاليًا في VS 2003...).أي نصائح؟

هل كانت مفيدة؟

المحلول

هل يمكن أن يكون ماكرو MYLOG عودته كائن functor العرف الذي يأخذ عدد متغير من الوسائط.

#include <string>
#include <cstdarg>

struct CLogObject {

  void operator()( const char* pFormat, ... ) const {
    printf( "[%s:%d] ", filename.c_str(), linenumber );
    va_list args;
    va_start( args, pFormat );
    vfprintf( stderr, pFormat, args );
    va_end( args );
  }

  CLogObject( std::string filename, const int linenumber )
    : filename( filename ), linenumber( linenumber )
  {}
  std::string filename;
  int linenumber;
};

#define MYLOG CLogObject( __FILE__, __LINE__ )


int _tmain(int argc, _TCHAR* argv[])
{

  MYLOG( "%s, %d", "string", 5 );
  return 0;
}

لاحظ أنه ليس من الصعب جدا لتخطي للمتغير من نوع آمنة لمسها من قبل <وأ href = "https://stackoverflow.com/questions/419559/is-this-possible-use-ellipsis-in-macro هل يمكن-أن-أن-تحويل-إلى قالب # 419828 "> هذه الإجابة : أنت لا تحتاج إلى أي حجج variadic بسبب تأثير تسلسل من operator<<

struct CTSLogObject {

  template< typename T >
  std::ostream& operator<<( const T& t ) const {
    return std::cout << "[" << filename << ":" << linenumber << "] ";
  }

  CTSLogObject( std::string filename, const int linenumber )
    : filename( filename ), linenumber( linenumber )
  {}
  std::string filename;
  int linenumber;
};
#define typesafelog CTSLogObject( __FILE__, __LINE__ )

int _tmain(int argc, _TCHAR* argv[])
{
  typesafelog << "typesafe" << ", " << 5 << std::endl;
  return 0;
}

نصائح أخرى

أسئلتك تناشد في الواقع إجابتين.تريد القيام بوظيفة التسجيل العامة، التي تعمل مثل printf ولكن يمكن تخصيصها بالكامل.لذا عليك:

  • يأخذ الماكرو عددًا متغيرًا من الوسائط
  • وظيفة تأخذ عددا متغيرا من الحجج

فيما يلي مثال التعليمات البرمجية الخاص بك الذي تم تعديله:

#include <stdio.h>
#include <stdarg.h>


class CLogClass
{
public:
    static void DoLogWithFileLineInfo( const char * fmt, ... )
    {
        va_list ap;
        va_start( ap, fmt );
        vfprintf( stderr, fmt, ap );
        va_end( ap );
    }

};


#define MYLOG(format, ...) CLogClass::DoLogWithFileLineInfo("%s:%d " format , __FILE__, __LINE__, __VA_ARGS__)

int main()
{
    MYLOG("Hello world!\n", 3); // you need at least format + one argument to your macro
    MYLOG("%s\n", "Hello world!");
    MYLOG("%s %d\n", "Hello world!", 3);
}

تم تقديم وحدات الماكرو المتغيرة في C99، لذلك ستعمل على المترجمين الذين يدعمون C99 أو C++0x.لقد قمت باختباره بنجاح باستخدام gcc 3.4.2 وVisual Studio 2005.

لقد كانت الحجج المتباينة للوظائف موجودة إلى الأبد، لذا لا داعي للقلق بشأن قابلية التوافق هنا.

ربما يكون من الممكن القيام بذلك باستخدام بعض نماذج البرمجة التعريفية ولكني لا أرى فائدة منها نظرًا لبساطة الكود أعلاه.

كملاحظة أخيرة، لماذا نستخدم طريقة ثابتة في فئة فارغة بدلا من وظيفة؟

class Log {
    stringstream buffer;
    public:
        class Proxy {
            public:
                Proxy(Log& p) : parent(p) {}
                template<class T>
                Proxy& operator,(T const& t) {
                    parent.buffer << t;
                    return *this;
                }
                ~Proxy() {
                    parent.buffer << endl;
                    cout << parent.buffer.str();
                    parent.buffer.str("");
                }
            private:
                CLog& parent;
        };

        template<class T>
        Proxy operator<<(T const& t) {
            buffer << t;
            return Proxy(*this);
        }
};

ويمكن تمديدها بشكل مسلي لكتابة الطوابع الزمنية، تحقق من loglevel، والكتابة إلى الملف، وما إلى ذلك.

وأو، ببساطة أكثر ولكن أقل مرونة:

class Log {
    public:
        class Proxy {
            public:
                template<class T>
                Proxy& operator,(T const& t) {
                    cout << t;
                    return *this;
                }
                ~Proxy() {
                    cout << endl;
                }
        };

        template<class T>
        Proxy operator<<(T const& t) {
            cout << t;
            return Proxy();
        }
};

والاستعمال:

Log log;
void f() {
     log << "hey, my age is ", age;
}

وأنا أميل إلى استخدام دالة خارجي مرئية عالميا بدلا من ماكرو في هذه الحالة، وحل القطع في هذه المهمة باستخدام va_list. انظر مشاركتي السابقة للحصول على مثال href="https://stackoverflow.com/questions/205529/cc-passing-variable-number-of-arguments-around#205584"> .

scroll top