这可以在宏中使用省略号吗? 可以转换成模板吗?

发布于 2024-07-10 22:12:17 字数 347 浏览 5 评论 0原文

实现了 CLogClass 来进行体面的日志记录后,我还定义了宏,但它仅适用于一个参数...

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

好吧,当使用超过 2 个参数调用时它会失败:(...是否有可能避免它?可以吗以某种方式转换为模板?

编辑: VS 2005 中引入了可变参数宏(但我目前在 VS 2003 中...)。

Having implemented CLogClass to make decent logging I also defined macro, but it works only with one parameter...

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

Well, it fails when called with more than 2 parameters :( ... Is it possible at all to avoid it? Can it be translated to templates somehow?

EDIT: Variadic macros were introduced in VS 2005 (But i'm currently in VS 2003...). Any advices?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

如梦 2024-07-17 22:12:17

您可以让 MYLOG 宏返回一个自定义仿函数对象,该对象采用可变数量的参数。

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

请注意,过渡到 这个答案:由于运算符<<的链接效应,您不需要任何可变参数。

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

You could have a MYLOG macro returning a custom functor object which takes a variable number of arguments.

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

Note that it's not so hard to step over to the type-safe variant touched by this answer: you don't need any variadic arguments due to the chaining effect of 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;
}
猛虎独行 2024-07-17 22:12:17

你的问题实际上有两个答案。 您想要执行通用日志记录功能,其工作方式类似于 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 成功测试了它。

函数的可变参数一直存在,所以这里不用担心兼容性。

可能可以通过一些模板元编程来做到这一点,但考虑到上面代码的简单性,我没有看到它的兴趣。

最后一点,为什么在空类中使用静态方法而不是函数?

Your questions actually appeals to two answers. You want to do the universal logging function, that works like printf but can be fully customise. So you need:

  • macro taking a variable number of arguments
  • function taking a variable number of arguments

Here is your code example adatapted:

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

Variadic macros have been introduced in C99, so it will work on compilers supporting C99 or C++0x . I tested it successfully with gcc 3.4.2 and Visual Studio 2005.

Variadic arguments to functions have been there forever so no worry about compability here.

It's probably possible to do it with some template meta-programmaing but I don't see the interest of it given the simplicity of the code above.

As a last note, why use a static method in an empty class instead of a function ?

鯉魚旗 2024-07-17 22:12:17
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);
        }
};

可以简单地扩展为写入时间戳、检查日志级别、写入文件等。

或者,更简单但不太灵活:

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

Can be trivially extended to write timestamps, check for loglevel, write to file, etc.

Or, more simply but less flexibly:

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();
        }
};

Usage:

Log log;
void f() {
     log << "hey, my age is ", age;
}
橘寄 2024-07-17 22:12:17

在这种情况下,我倾向于使用全局可见的 extern 函数而不是宏,并使用 va_list 解析该函数​​中的省略号。 请参阅我之前的帖子,了解如何实现此目标的示例

I would tend to use a globally visible extern function rather than a macro in this instance, and resolve the ellipsis in this function using a va_list. See my previous post for an example on how to achieve this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文