流变量作为C ++中的函数参数

时间:2015-09-16 13:23:18

标签: c++ stream type-conversion

当您将变量流式传输到输出流(如cout)时,类型转换是自动的。我想弄清楚的是如何通过函数调用来做到这一点,例如:

inline void DEBUG(ostream& s)   // Don't know if this prototype is appropriate
{
  cout << s;
}


main()
{
  int i = 5;

  DEBUG("The value is: " << i << endl); // This doesn't compile

  DEBUG("The value is: " + i + endl); // Neither does this
}

我在这里发现了类似的问题,但它们都涉及将流对象作为参数传递,而我正在尝试将“流数据”传递给已经拥有流对象的函数,所以反过来说。这甚至可能吗?我不想诉诸显式类型转换。我还找到了this question,但如果可以避免的话,我真的不想写一个完整的记录器类。

目前我正在将其作为宏实现,但是如果可能的话我宁愿使用内联函数。

#define DEBUG(s)    (cout << s)

2 个答案:

答案 0 :(得分:0)

当然不会编译。这有很多原因。

首先,运营商&lt;&lt;没有为标准流定义,并且您正在尝试这样做:在DEBUG()中将流流式传输到流中。 (双关语)。

第二,运营商&lt;&lt;没有为字符串文字定义,你试图在这里调用它:

"The value is: " << i
顺便说一下,

+也没有为文字定义。

要实现您想要查看的语义,您必须从流开始。首先需要将字符串文字转换为流,然后才能应用&lt;&lt;它。这是实现您想要的唯一途径。

编辑:

既然我理解了理由,我可以给出更好的答案。人们尝试不同程度地分离不同级别的调试有很多种方法,并且有几个目标用于此目的(log4cpp,boost.log仅举几例)。在开始实现自己的日志记录之前,我肯定会建议您查看这些日志。良好的日志记录远不仅仅是调试级别。

如果您出于任何原因想要使用自己的自制软件,可以使用以下几种接收方式:

  • 使用您自己的记录器类(非常罕见的示例之一,靠近 单身! Singleton是合适的)。你可以设置 记录级别在您的应用程序的开始,而不仅仅是 调用Logger :: debug()&lt;&lt; ...
  • 使用宏丰富上述解决方案。函数的问题在于,与宏不同,它们会松散上下文。因此,如果您想记录日志记录调用的文件和行号(通常也会这样做!),您可能希望执行LOG_DEBUG&lt;&lt; ...;这里LOG_DEBUG会扩展成类似Logger :: debug()&lt;&lt; __FILE__&lt;&lt; “:”&lt;&lt; __LINE__&lt;&lt; ....
  • 完成此操作后,您会看到有时您会调用&lt;&lt;&lt;&lt;链。此时您可能会意识到,无论您的调试级别如何,都会调用这些函数,并且可能认为您不希望在未启用调试时调用它们(LOG_DEBUG&lt;&lt;“对象现在是”&lt; &lt; object.serialize();因此,当调试级别不匹配时,您将希望丰富LOG_DEBUG宏以不执行任何操作。
  • 传奇继续......准备好使用图书馆了吗?

答案 1 :(得分:0)

那么,(至少某些)日志库会做的是创建一个充当流的临时代理对象:

#include <iostream>

struct LoggerProxy {
    LoggerProxy(const char* file, int line)
    {
        std::cout << "File " << file << ", line " << line << ": ";
    }

    template<typename T>
    LoggerProxy& operator<<(T&& t)
    {
        std::cout << t;
        return *this;
    }
};

#define LOG_DEBUG LoggerProxy{__FILE__, __LINE__}

int main()
{
    LOG_DEBUG << "Value is: " << 4;
}

你可以用这个来做很多花哨的事情,例如调试级别检查,输出到不同的流或多个后端(例如同时输出到std :: cout / cerr和日志文件)等等。

相关问题