这里是一个简单的问题。我一直在搜索但没有结果。
以下是更多信息:
stringstream report_string;
report_string << "some string here...";
我的代码本身有各种条件用于给report_string变量赋值。
我想检查它是否被赋过值。
这里是一个简单的问题。我一直在搜索但没有结果。
以下是更多信息:
stringstream report_string;
report_string << "some string here...";
我的代码本身有各种条件用于给report_string变量赋值。
我想检查它是否被赋过值。
myStream.rdbuf()->in_avail()
可以用来获取 stringstream
中待读取的字符数量,你可以使用它来检查你的 stringstream
是否为空。我假设你实际上并不想检查值为 null
。
例如,如果你想从 stringstream
中提取一个 int
,然后查看是否有任何剩余的字符(即非数字),你可以检查 myStream.rdbuf()->in_avail() == 0
。
这是否与你尝试做的事情类似?我不确定是否有更好的方法,但我过去曾经这样做,它对我有效。
https://en.cppreference.com/w/cpp/io/basic_streambuf/in_avail
编辑:我看到你刚刚更新了你的问题。
continue
并忘记清除它……) - Matthieu M.rdbug()->in_avail()
总是返回0,就像GNU g++在网上的各个地方所描述的那样。我在http://www.cpp.re/forum/general/233925/找到了Cubbi的评论很有启发性:“它报告获取区域的大小(意思是,可以在不进行虚拟调用的情况下读取多少字节)……没有虚拟函数调用,写操作不可能触及流的读取端。”我的用例简单/有限,我不介意扔掉字符串缓冲区中的任何字符,所以我可以简单地测试`my_stream.readsome(&test_char, 1) == 0`以确认它为空。 - sage这种方法效率高,应该也适用于输出字符串:
ostringstream report_string;
if (report_string.tellp() == 0) {
// do something
}
if (report_string.tellp() == std::streampos(0))
。 - Oz Solomonseekp()
。此外,我认为OP的问题是关于在tellp() != 0
时做某事。 - Alexis Wilkestd::streampos(0)
比直接使用 0
好吗?我真的很感兴趣。 - Yurimstd::fpos
(std::streampos
的实现类)没有标准正式要求具有接受 int 参数的构造函数。这意味着,根据您特定的标准库实现,0 可能会或可能不会隐式转换为 streampos
。 - Oz Solomonstreampos
通过“P p = o”隐式可转换,其中“P”是您的fpos
类型(streampos
-things),而“o”是您的streamoff
类型(int
-things)。在尝试猜测对未知编译器的支持之前,我会始终考虑YAGNI。 - c z一个简单的检查是看流的字符串内容是否为空:
#include<assert.h>
#include<sstream>
int main(){
std::stringstream report_string;
report_string << ""; // an empty strin g
//emptiness check of stringstream
assert(report_string.str().empty());
}
str()
的问题在于它可能会创建一个巨大的内存块,只是为了检查它是否为空。 - Alexis Wilke一种方法是检查内部字符串的大小并与零进行比较。请注意,这与AusCBlock建议的myStream.rdbuf()->in_avail()
不同;in_avail()可以返回与流的实际大小不同的值(例如,如果内部缓冲区由多个非连续内存块表示)。特别地,in_avail()
原则上可以在非空缓冲区中返回零(stringbuf规范可能进一步限制了这一点;我没有详细检查过)。
stringstream report_string;
if ( !(report_string.eof()) )
cout << "report_string EMPTY! \n";
eof()
对于 std::stringstream
总是为假。文档中也没有看到任何相关说明。但即使它不为空,它的行为也是如此。 - Yuvalwhile (in.eof())
经常出现问题相同:只有在之前的输入尝试在成功之前遇到 eof()
时,才会设置 eof()
。因此,如果例如 report_string >> my_int
从输入中读取了一个数字,并且最后一位是流中的最后一件事,那么 eof()
将为 true
。但是,如果您使用 char c = report_string.get();
获取最终字符,则它将在文件结束时成功而不尝试执行任何操作,eof()
将 不 为 true。演示:这里。 - Tony Delroy通常情况下,使用...是合理且易读的。
report_string.str().empty()
...但这可能涉及动态分配和复制整个字符串到临时位置,最后又被抛弃。
如果性能很重要,另一个选择是...
report_string.peek() == decltype(report_string)::traits_type::eof()
该方法用于查找流中尚未提取的字符,忽略已经成功解析/提取的输入
report_string.str().empty()
不同,后者仍然“看到”已提取的输入如果先前的解析使流处于未清除的fail
状态,则无论是否有更多未提取的字符,此方法都将返回eof()
report_string.peek() == std::char_traits<char>::eof()
对我来说做得很好(即至少针对检查stringstream是否未修改的特殊情况)- 我认为 std::char_traits <char> ::eof()
可能与decltype(report_string)::traits_type ::eof()
相同。如果检查失败,则我有兴趣将report_string.rdbuf()
传递给std::cout
以避免额外的复制,因此调用report_string.str()
将使该优化变得无意义。(未经检查调用rdbuf
具有副作用,并可能引发异常)。 - Apriorireport_string
实例化为char
,std::char_traits<char>::eof()
将是相同的-你的方法更简单,但如果report_string
的类型改变了,那么就需要额外的维护点-总的来说区别不大。关于rdbuf()
可能会抛出异常的有趣见解-我以前并没有想到!干杯 - Tony Delroy>>
运算符或 std::getline
方法...如果流是空的,它们将返回false,因此您可以编写以下代码: "最初的回答"stringstream report_string;
foo(report_string)// some functions which may or may not write to report_string
string single_report;//string to read to
bool empty=true;//First assume it was empty
while(getline(report_string,single_report))//Alternatively use report_string>>single_report if you don't want entire lines
{
empty=false;//...it wasn't empty
bar(single_report);//Do whatever you want to do with each individual appended line
}
if (empty)
{
//... whatever you want to do if the stream was empty goes here
}
需要注意的是,这种方法假设您打算循环使用stringstream;如果不是这样,那么就不能使用这种方法。
最初的回答:
请注意,这种方法假定您计划循环使用stringstream;如果不是,则无法使用此方法。
还有其他的方法吗?
如果您将ostringstream作为可选类型,则可以在使用它之前检查它是否已被分配。
想象一个名为lazy<>
的类,它在需要时懒惰地构造对象,然后我们可以这样做:
int main()
{
using namespace std;
auto oss1 = lazy<std::ostringstream>();
auto oss2 = lazy<std::ostringstream>();
use(oss1) << "Hello";
if (oss1) cout << use(oss1).str() << endl;
if (oss2) cout << use(oss2).str() << endl;
if_used(oss1, [](auto& ss) { cout << ss.str() << endl; });
if_used(oss2,
[](auto& ss) { cout << ss.str() << endl; },
[](auto& oss) { cout << "oss2 is not used" << endl; });
use(oss2) << "Goodbye";
if_used(oss2, [](auto& ss) { cout << ss.str() << endl; });
return 0;
}
产生此输出:
Hello
Hello
oss2 is not used
Goodbye
优点:
在不使用时,无需构建冗余的stringstream
。
如果后续使用未使用的stringstream(通过const引用),则可选项提供异常。
下面是带有可定制构造函数的完整示例:
我已经使用了std::experimental
来进行可选项处理,但您也可以轻松使用boost::optional
。
#include <iostream>
#include <experimental/optional>
#include <utility>
#include <type_traits>
#include <sstream>
using std::experimental::optional;
namespace detail {
template<class T, class Constructor>
struct lazy final
{
template<class Con , std::enable_if_t< not std::is_same<std::decay_t<Con>, lazy>::value > * = nullptr>
lazy(Con&& con)
: _constructor(std::forward<Con>(con))
{}
T& get() {
if (not bool(_opt)) {
_opt = _constructor();
}
return *_opt;
}
const T& get() const {
return *_opt;
}
bool used() const {
return bool(_opt);
}
operator bool() const {
return used();
}
private:
Constructor _constructor;
optional<T> _opt;
};
template<class T>
struct default_construct {
T operator()() const { return T(); }
};
struct no_action {
template<class T>
void operator()(T&) const { }
};
}
template<class T, class Constructor = detail::default_construct<T> >
auto lazy(Constructor&& con = detail::default_construct<T>())
{
return detail::lazy<T, std::decay_t<Constructor>>(std::forward<Constructor>(con));
}
template<class T, class Constructor>
auto& use(detail::lazy<T, Constructor>& l)
{
return l.get();
}
template<class T, class Constructor>
auto& use(const detail::lazy<T, Constructor>& l)
{
return l.get();
}
template<class T, class Constructor, class F, class Else = detail::no_action>
void if_used(detail::lazy<T, Constructor>& l, F&& f, Else&& e = detail::no_action())
{
if (l.used())
f(l.get());
else
e(l);
}
template<class T, class Constructor, class F, class Else = detail::no_action>
void if_used(const detail::lazy<T, Constructor>& l, F&& f, Else&& e)
{
if (l.used())
f(l.get());
else
e(l);
}
int main()
{
using namespace std;
auto oss1 = lazy<std::ostringstream>();
auto oss2 = lazy<std::ostringstream>();
use(oss1) << "Hello";
if (oss1) cout << use(oss1).str() << endl;
if (oss2) cout << use(oss2).str() << endl;
if_used(oss1, [](auto& ss) { cout << ss.str() << endl; });
if_used(oss2,
[](auto& ss) { cout << ss.str() << endl; },
[](auto& oss) { cout << "oss2 is not used" << endl; });
use(oss2) << "Goodbye";
if_used(oss2, [](auto& ss) { cout << ss.str() << endl; });
return 0;
}