C++ 我是否可以使用流运算符重写日志宏以使用C++;模板功能?

C++ 我是否可以使用流运算符重写日志宏以使用C++;模板功能?,c++,macros,effective-c++,C++,Macros,Effective C++,我们的项目使用宏在一行语句中简化日志记录,如下所示: DEBUG_LOG(TRACE_LOG_LEVEL, "The X value = " << x << ", pointer = " << *x); 而且 template<typename WhatT> inline void DEBUG_LOG(LogLevel aLogLevel, WhatT aWhat) { ... } 模板内联无效调试日志(日志级别aLogLevel,W

我们的项目使用宏在一行语句中简化日志记录,如下所示:

DEBUG_LOG(TRACE_LOG_LEVEL, "The X value = " << x << ", pointer = " << *x);
而且

template<typename WhatT> inline void DEBUG_LOG(LogLevel aLogLevel, WhatT aWhat) {
    ...  }
模板内联无效调试日志(日志级别aLogLevel,WhatT aWhat){
...  }

无效(上述两次重写都不会针对第一个示例中的日志代码编译)。还有其他想法吗?这能做到吗?还是最好将其保留为宏?

不,不可能将该宏作为模板重写,因为您使用的是运算符(将该特定宏转换为函数的问题是类似于
“X值=”日志记录仍然是少数几个无法完全删除宏的地方之一,因为您需要调用站点信息(
\uuuuuu LINE\uuuuuu
\uuu FILE\uuuuu
,…),而这些信息在其他情况下是不可用的。另请参阅

但是,您可以将日志逻辑移到一个单独的函数(或对象)中,通过宏只提供调用站点信息,甚至不需要模板函数

#define DEBUG_LOG(Level, What) \
  isEnabled(Level) && scoped_logger(Level, __FILE__, __LINE__).stream() << What

公开底层的
std::stringstream
对象可以省去我们编写自己的
操作符的麻烦,我们只需将其保留为一个宏即可。更重要的是,函数
\uuuuuuuuuuuuuuu文件和
\uuuuuuuuuuuuuuuuuuuuu行
将无法按预期工作。我喜欢这种基于类的方法,但它可能无法完全适应当前的问题ce宏,如
\uuuuu FILE\uuuuuuu
\uuuuu LINE\uuuuuuu
将不再工作。DEBUG\u LOG可以是一个宏,它创建临时记录器对象,并将跟踪日志级别、行和文件作为参数。我非常喜欢这种方法,以及DEBUG\u LOG(…)宏被视为要流式处理的日志对象。但我可能不会使用这种方法,除非我有时间回去检查所有文件并制作适当的MOD。虽然我非常喜欢@svenihoney的答案,因为它似乎是一种更具OO风格的方法,但我最有可能使用这种方法,因为它影响最小修改现有代码。
template<typename WhatT> inline void DEBUG_LOG(LogLevel aLogLevel, WhatT aWhat) {
    ...  }
DEBUG_LOG(TRACE_LOG_LEVEL) << "The X value = " << x << ", pointer = " << *x << logger::flush;
#define DEBUG_LOG(Level, What) \
  isEnabled(Level) && scoped_logger(Level, __FILE__, __LINE__).stream() << What
struct scoped_logger
{
  scoped_logger(LogLevel level, char const* file, unsigned line)
    : _level(level)
  { _ss << file << "(" << line << ") [" << getpid() << "] : "; }

  std::stringstream& stream(){ return _ss; }
  ~scoped_logger(){ logger::log(_level, _ss.str()); }
private:
  std::stringstream _ss;
  LogLevel _level;
};