std::stringstream 作为参数
我对 C++ 语言有点陌生。我正在编写一个用于记录到文件的实用程序类。它工作得很好,只是现在我想通过使其更方便使用来增强它(例如,将字符串流传递给日志函数)。
这就是我一直在尝试的方法,但没有成功。
定义:
void LogStream( std::stringstream i_Log ){ m_FileHandle << i_Log << std::endl; }
调用:
m_LogObject->LogStream( "MKLBSearchEngine::Search( " << x << ", " << i_Filter << " ) - 未找到结果” );
I'm somewhat new to the C++ language. I'm writing a utility class for logging to file. It works beautifully except that now I would like to enhance it by making it more convenient to use (e.g. pass stringstreams to a log function).
This is what I've been trying and it hasn't worked.
definition:
void LogStream( std::stringstream i_Log ){
m_FileHandle << i_Log << std::endl;
}
call:
m_LogObject->LogStream( "MKLBSearchEngine::Search( " << x << ", " << i_Filter << " ) - No Results Found" );
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您的解决方案存在几个问题。第一个是你是
按值传递
stringstream
,并且不支持复制。你需要通过参考。第二个是在调用站点,返回值
operator<<
重载是ostream&
,而不是stringstream
,并且因为stringstream
不是ostream&
的基类(这是另一种方式round),您无法初始化
stringstream
(或stringstream&
)与它。最后,没有
operator<<
需要一个stringstream
作为右侧参数,因此语句中LogStream
功能无法工作。最后,这将有点无论如何对于用户来说都很尴尬。日志
operator<<
都是非会员,使用
ostream&
非常量引用作为第一个参数,所以你不能使用临时参数作为左参数来调用它们。 (在您的示例调用中,
当然,无论如何,您忘记创建 std::ostringstream ;它
不会编译,因为没有重载
<<
,它需要一个char
或const[]
char const*
作为其左侧操作数。)几乎所有这些问题都有解决方法。某物
like:
处理除最后一个之外的所有问题;最后必须处理
由客户端执行,类似于:(
对 std::ostream::flush() 的调用返回一个非常量引用
流,可用于进一步初始化
std::ostream&
。虽然您无法使用临时变量初始化非常量引用,
您可以在其上调用非常量成员函数。)
对于客户端代码来说,这种尴尬使我通常更喜欢
更复杂的解决方案。我定义了一个特殊的 LogStreamer 类,
类似于:
然后
客户端代码可以编写:
在我自己的代码中:日志对象始终是单例,调用是
通过宏,将
__FILE__
和__LINE__
传递给LogStream()
函数,最终目标ostream是一个特殊的streambuf,带有
特殊函数,由
LogStream()
调用,它接受一个文件名和一个行号,在开始时输出它们以及时间戳
下一行输出,并缩进所有其他行。一个过滤
Streambuf 类似于:(
函数
now()
当然,返回一个std::string
,其中时间戳。或者一个
struct tm
,并且您已经为tm
编写了一个<<
。)There are several problems with your solution. The first is that you're
passing
stringstream
by value, and it doesn't support copy. You needby reference. The second is that at the call site, the return value of
the
operator<<
overloads isostream&
, notstringstream
, and sincestringstream
isn't a base class ofostream&
(it's the other wayround), you can't initialize the
stringstream
(or thestringstream&
)with it. And finally, there's no
operator<<
which takes astringstream
as the right hand parameter, so the statement in theLogStream
function can't work. Finally, this is going to be somewhatawkward for the user anyway. A log of
operator<<
are non-members,with an
ostream&
non-const reference as first argument, so you can'tcall them with a temporary as the left argument. (In your example call,
of course, you forgot to create the
std::ostringstream
anyway; itwon't compiler because there is no overload of
<<
which takes achar
or aconst[]
char const*
as its left hand operand.)There are work-arounds for almost all of these problems. Something
like:
handles all of the problems except the last; the last has to be handled
by the client, something like:
(The call to
std::ostream::flush()
returns a non-const reference tothe stream, which can be used to initialize further
std::ostream&
.And while you can't initialize a non-const reference with a temporary,
you can call a non-const member function on it.)
The awkwardness of this for the client code makes me generally prefer a
more complex solution. I define a special
LogStreamer
class,something like:
and
The client code can then write:
In my own code: the log object is always a singleton, the call is
through a macro, which passes
__FILE__
and__LINE__
to theLogStream()
function, and the final target ostream is a special streambuf with a
special function, called by
LogStream()
, which takes a filename and aline number, outputs them, along with the time stamp, at the start of
the next line output, and indents all other lines. A filtering
streambuf with something like:
(The function
now()
, of course, returns astd::string
with thetimestamp. Or a
struct tm
, and you've written a<<
fortm
.)你的设计有问题。您不想接受流作为参数,要么接受字符串,要么让您的类表现为流(或两者)。
如果您使对象表现为流,则执行以下操作:
为此,只需重写
<<
运算符即可。You have a problem with your design. You don't want to accept a stream as a parameter, either accept a string, or make your class behave as a stream (or both).
If you make your object behave as a stream, then you do the following:
To do that, simply override the
<<
operator.您的调用应该如下所示,
因为您需要创建要传递给函数的 stringstream 对象。
此调用意味着您已经有了所需的输出流,因此我还建议您更改类设计以使用
operator<<
进行日志记录,除非它已经过载。Your call should look like
since you need to create your stringstream object that you will be passing to the function.
This call implies that you already have a desired output stream so i'd also recommend you changing your class design to use
operator<<
for logging unless it is already overloaded.您的函数调用将不起作用,因为
"MKLBSearchEngine::Search( "
的类型为 const char* 并且<<
运算符没有重载。它也不适用于std::string("MKLBSearchEngine::Search( ")
,因为std::string
也没有这样的运算符。可以做的是调用它std::stringstream("MKLBSearchEngine::Search( ")
,它将第一个参数转换为流,以便以下运算符在此流上工作。但正如其他人指出的那样,您必须将函数参数设置为 const 引用,因为流不可复制(即使这样,效率也会很低)。此外,仅将std::stringstream
写入文件也不会执行您想要的操作(如果)。无论如何它都有效),相反你必须获取其内容(底层 std::string )。因此,您的所有代码应该如下所示:但您也可以只使用 LogString(const std::string &)< /code> 并让该函数的用户自己调用
stream.str()
。Your function call won't work, as
"MKLBSearchEngine::Search( "
is of type const char* and that has no overload for the<<
operator. It won't work withstd::string("MKLBSearchEngine::Search( ")
either, as alsostd::string
doesn't have such an operator. What you can do is call it withstd::stringstream("MKLBSearchEngine::Search( ")
, which converts the first argument to a stream, such that the following operators work on this stream. But as others pointed out, you will have to make the function argument a const reference, as streams are not copyable (even then it would be quite inefficient). Also just writing astd::stringstream
into the file won't do what you want (if it works anyway), instead you have to take its contents (the underlyingstd::string
). So all in all your code should look like:But you could also just use a
LogString(const std::string &)
and let the user of this function callstream.str()
himself.您无法按值传递流对象(因为它们不可复制),因此您需要传递(并存储)引用:
这可能不会达到您所期望的效果(它可能会打印 i_Log 的地址,出于相当模糊的原因)。
如果您的目的是从字符串流中取出内容,这可能会满足您的要求:
You can't pass stream objects by value (since they are not copyable), so you need to pass by (and store) references:
This probably won't do what you're expecting though (it will probably print an address of i_Log, for rather obscure reasons).
If your intention is to take stuff OUT of the stringstream, this might do what you want:
您正在按值传递
std::stringstream
实例。您希望避免复制并通过引用(或指针)传递它。例如:阅读有关 C++ 参考的更多信息。
You are passing
std::stringstream
instance by value. You want to avoid copying and pass it by reference (or pointer). For example:Read more about C++ references.