C++ 使水流短路

C++ 使水流短路,c++,c++11,conditional,iostream,C++,C++11,Conditional,Iostream,该应用程序有一个日志记录系统,允许在运行时启用或禁用其模块的日志记录功能。日志命令接受输入上的流(是一个安全的替代“Simultf”);几乎没有任何恼人的情况比您的调试系统是崩溃的原因。 问题是,如果我执行以下操作: logger.Trace << "Requests pending:" << buffer.findRequests(); 它不漂亮,也不舒服。我可以用使用if的宏替换它,或者用&&短路的宏替换它,稍微好一点(可以用作右值,下面的流哲学在禁用流时返回bo

该应用程序有一个日志记录系统,允许在运行时启用或禁用其模块的日志记录功能。日志命令接受输入上的流(是一个安全的替代“Simultf”);几乎没有任何恼人的情况比您的调试系统是崩溃的原因。 问题是,如果我执行以下操作:

 logger.Trace << "Requests pending:" << buffer.findRequests();
它不漂亮,也不舒服。我可以用使用
if
的宏替换它,或者用
&&
短路的宏替换它,稍微好一点(可以用作右值,下面的流哲学在禁用流时返回bool false):

两者都不是特别漂亮或安全。一位同事建议:

  logger.Trace([&](f){f << "Requests pending:" << buffer.findRequests();});

确实可以使用Trace([&](f){f宏,但是您需要像宏一样的函数,将输出作为参数,并且需要确保它是一条语句

第二部分,确保宏体是一条语句,很简单,通常使用
do{…}while(false)
来完成

在宏中使用参数也不难,只要参数中没有逗号。逗号限制包括在宏参数中使用函数调用和自己的参数,预处理器非常愚蠢,因为在宏参数中使用任何逗号作为宏参数的分隔符

在其最简单的形式中,不必考虑逗号限制,宏可以看起来像

#define TRACE(output)                   \
    do                                  \
    {                                   \
        if (logger.Trace.Enabled())     \
        {                               \
            logger.Trace << output;     \
        }                               \
     } while (false)
do{…}while(false)
部分很可能会被编译器优化掉,留给您一个简单的
if
检查。如果
logger.Trace.Enabled()
返回
false
,那么除了该检查之外,不应该发生任何事情

如果您有一个能够使用C++11或更高版本的编译器,它应该支持这一功能,这将帮助您克服宏参数中逗号的限制

使用可变宏时,宏将改为如下所示:

#define TRACE(...)                       \
    do                                   \
    {                                    \
        if (logger.Trace.Enabled())      \
        {                                \
            logger.Trace << __VA_ARGS__; \
        }                                \
     } while (false)
定义跟踪(…)\ 做\ { \ if(logger.Trace.Enabled())\ { \
logger.Trace我解决了这个问题。最后,我用这个接口和相关的宏创建了一个类
Log

class Log
{
  public:
    static bool trace_is_active();
    static bool debug_is_active();
    static bool info_is_active();
    static bool warning_is_active();
    static bool error_is_active();
    static void write_as_trace(const std::string& msg);
    static void write_as_debug(const std::string& msg);
    static void write_as_info(const std::string& msg);
    static void write_as_warning(const std::string& msg);
    static void write_as_error(const std::string& msg);
};

#define LOG_TRACE(X) {if(Log::trace_is_active()){std::ostringstream o__;o__<<X;Log::write_as_trace(o__.str());}}
#define LOG_DEBUG(X) {if(Log::debug_is_active()){std::ostringstream o__;o__<<X;Log::write_as_debug(o__.str());}}
#define LOG_INFO(X) {if(Log::info_is_active()){std::ostringstream o__;o__<<X;Log::write_as_info(o__.str());}}
#define LOG_WARNING(X) {if(Log::warning_is_active()){std::ostringstream o__;o__<<X;Log::write_as_warning(o__.str());}}
#define LOG_ERROR(X) {if(Log::error_is_active()){std::ostringstream o__;o__<<X;Log::write_as_error(o__.str());}}
类日志
{
公众:
静态布尔跟踪_处于活动状态();
静态bool debug_处于活动状态();
静态布尔信息处于活动状态();
静态布尔警告处于活动状态();
静态布尔错误_处于活动状态();
静态无效写为跟踪(const std::string&msg);
静态无效写为调试(const std::string&msg);
静态无效写入为信息(const std::string&msg);
静态无效写为警告(const std::string&msg);
静态无效写入错误(const std::string&msg);
};

#定义LOG_TRACE(X){if(LOG::TRACE_is_active()){std::ostringstream o_uu;o_u我认为闭包是唯一的方法。在引入闭包之前,我必须解决同样的问题,最后我又回到了宏和C风格函数调用上。“从逻辑上讲,这很好,但从语法上来说绝对可怕。”呵呵,欢迎来到C++@LightnessRacesinOrbit:很高兴我没有用
来结束。昨天偶然发现了这个问题,让我困惑了好一阵子。事实上
@SF.:“C++11到底为什么要扩展有向图和三向图集?”没有t@LightnessRacesinOrbit:哦,等等,它没有添加任何新的标记。它只是修改了一个标记的解释。当解析器满足字符序列时,<本身被视为预处理标记,而不是替代标记的第一个字符。您可以在不使用变量宏的情况下解决此问题。定义
TRACE
作为不带参数的宏,其中
TRACE
替换为对函数的调用,该函数返回一个函数指针,指向一个带变量参数的函数。根据启用的日志记录,让该函数调用返回两个函数中的一个。如果启用日志记录,则返回一个实际记录数据的函数。如果如果未启用日志记录,则返回一个函数,该函数只返回而不执行任何操作:
void(*traceFunc)(const char*fmt,…)
then
#define traceFunc()<代码> >不做C++ IO,though@AndrewHenle但是,即使禁用了日志记录,日志消息仍然会被计算,然后被丢弃,OP希望避免这种情况。@el.pescado True。我认为不使用变量宏就不可能完全解决这方面的问题。看到这样的解决方案肯定会很有趣。纯C++IO解决方案也很有趣——我的意思是一个完全不需要C风格括号的解决方案——它只使用
@AndrewHenle:我知道有一个不使用()。它只使用{}。
试试{logger.Trace
TRACE("Requests pending:" << buffer.findRequests());
#define TRACE(...)                       \
    do                                   \
    {                                    \
        if (logger.Trace.Enabled())      \
        {                                \
            logger.Trace << __VA_ARGS__; \
        }                                \
     } while (false)
class Log
{
  public:
    static bool trace_is_active();
    static bool debug_is_active();
    static bool info_is_active();
    static bool warning_is_active();
    static bool error_is_active();
    static void write_as_trace(const std::string& msg);
    static void write_as_debug(const std::string& msg);
    static void write_as_info(const std::string& msg);
    static void write_as_warning(const std::string& msg);
    static void write_as_error(const std::string& msg);
};

#define LOG_TRACE(X) {if(Log::trace_is_active()){std::ostringstream o__;o__<<X;Log::write_as_trace(o__.str());}}
#define LOG_DEBUG(X) {if(Log::debug_is_active()){std::ostringstream o__;o__<<X;Log::write_as_debug(o__.str());}}
#define LOG_INFO(X) {if(Log::info_is_active()){std::ostringstream o__;o__<<X;Log::write_as_info(o__.str());}}
#define LOG_WARNING(X) {if(Log::warning_is_active()){std::ostringstream o__;o__<<X;Log::write_as_warning(o__.str());}}
#define LOG_ERROR(X) {if(Log::error_is_active()){std::ostringstream o__;o__<<X;Log::write_as_error(o__.str());}}
//...
LOG_WARNING("The variable x = " << x << " is out of range");
//...
LOG_DEBUG("The inverse of the matrix is inv(m) = " << std::endl << inv(m) << std::endl);