C++ 如何初始化 std::stringstream?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21924156/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 23:52:47  来源:igfitidea点击:

How to initialize a std::stringstream?

c++stringstream

提问by Dragons_Lair5

I need to concatenate a string with integers. To do that I'm using stringstreamin the following way:

我需要用整数连接一个字符串。为此,我使用stringstream以下方式:

int numPeople = 10;
stringstream ss;
ss << "Number of people is " << numPeople;

And that worked. But I was trying to do it in the way below:

那奏效了。但我试图通过以下方式做到这一点:

int numPeople = 10;
stringstream ss << "Number of people is " << numPeople;

And I was getting the following error: "expected initializer before '<<' token"

我收到以下错误:“ '<<' 标记之前的预期初始化程序

Why was I getting this error? Why can't I assign the stringstreamvalue at the same time I declare it?

为什么我收到这个错误?为什么不能stringstream在声明值的同时赋值?

回答by Tony Delroy

stringstream ss << "Number of people is " << numPeople;

Why can't I assign the stringstreamvalue at the same time I declare it?

为什么不能stringstream在声明值的同时赋值?

This is similar to hoping this would work:

这类似于希望这会起作用:

int x + 3 + 9;

The problem

问题

When you're both defining and giving a value to an object, C++ lets you call the constructor, which requires a comma-separated list of expressions. For convenience the Type variable = value;notation is elided to call Type variable(value);, but only works for a single value.

当您既定义对象又为其赋值时,C++ 允许您调用构造函数,这需要以逗号分隔的表达式列表。为方便起见,Type variable = value;省略了 call的符号Type variable(value);,但仅适用于单个值。

For int, you can easily correct the code:

对于int,您可以轻松更正代码:

int x = 3 + 9;

...and it works because "3 + 9" can be evaluated independently first to give a sane value to store in x. The compiler's behaviour for operator +on ints does what we want: it produces the intresult we then want to store in x. But if you try that for stringstream...

...它之所以有效,是因为可以首先独立评估“3 + 9”以给出一个合理的值来存储在x. s操作符的编译器行为做我们想要的+int:它产生int我们想要存储的结果x。但是,如果您尝试这样做stringstream...

stringstream ss = "Number of people is " << numPeople;  // BROKEN

...it won't work, because "Number of people is " << numPeopleneeds to be evaluated first but is illegal - you'll get an error like "error C2296: '<<' : illegal, left operand has type 'const char [20]'" - it won't give a useful value for the stringstreamconstructor. The problem is that the compiler's still trying to apply the bitwise shift operator, which only makes sense for numbers, as the overloads for <<that we'd want to apply require a left-hand argument of type ostream&. C++ requires the value being evaluated on the right of =to be evaluated independently of the assignment that's eventually done with the resultant value, and at that point the type of the variable being constructed is not relevant to the way evaluation is attempted on the expression being assigned.

...它不会工作,因为"Number of people is " << numPeople需要先进行评估但这是非法的——你会得到一个类似“ error C2296: '<<' : illegal, left operand has type 'const char [20]'”的错误——它不会为stringstream构造函数提供有用的值。问题是编译器仍在尝试应用按位移位运算符,这仅对数字有意义,因为<<我们想要应用的重载需要类型为 的左侧参数ostream&。C++ 要求在 右边=被评估的值独立于最终对结果值完成的赋值进行评估,并且此时正在构造的变量的类型与尝试对被赋值的表达式进行评估的方式无关.

A solution

一个办法

It's a bit of a chicken-and-egg problem here, because you kind of need to combine the right-hand values you want in the stringstreamto call the stringstream's constructor, but for that you need... a stringstream. You can actually pull that off with a temporary stringstream:

这里有点像鸡和鸡蛋的问题,因为您需要在 中组合您想要的右侧值stringstream来调用stringstream的构造函数,但为此您需要... a stringstream。你实际上可以用一个临时的来完成它stringstream

static_cast<std::ostringstream&&>(std::ostringstream() << "Number of people is " << numPeople)

The cast is unfortunately needed because the operator<<overloads handle stringstreams via references to their ostreambase class, returning an ostream&, so you need to cast back to the stringstreamtype manually, so you can then invoke the std::stringstreammove constructor...

不幸的是,需要强制转换,因为operator<<重载stringstream通过对ostream基类的引用处理s ,返回ostream&,因此您需要stringstream手动转换回该类型,然后您可以调用std::stringstream移动构造函数...

The complete one-liner construction is then...

完整的单线结构然后...

std::stringstream ss(static_cast<std::ostringstream&&>(std::ostringstream() << "Number of people is " << numPeople));

...but that's too hideous to contemplate.

......但这太可怕了,无法考虑。

Making the solution (arguably) less hideous

使解决方案(可以说)不那么可怕

Depending on your sensibilities, you may feel a macro helps or is worse...

根据您的感受,您可能会觉得宏有帮助或更糟...

#define OSS(VALUES) \
    static_cast<std::ostringstream&&>(std::ostringstream() << VALUES)

std::stringstream ss(OSS("Number of people is " << numPeople));

FWIW, you could also use the macro to create strings...

FWIW,您还可以使用宏来创建字符串...

std::string s(OSS("Number of people is " << numPeople).str()); 

An (arguably) better practice

一种(可以说是)更好的做法

Just create the stringstream- optionally providing a single stringto the constructor - then use operator<<in a second statement:

只需创建stringstream- 可选地为string构造函数提供一个- 然后operator<<在第二个语句中使用:

std::stringstream ss;
ss << "Number of people is " << numPeople;

This is much easier to read. With move construction, after optimisation there's likely no performance reasons for preferring two statements.

这更容易阅读。使用移动构造,在优化之后可能没有首选两个语句的性能原因。

An alternative

替代

C++11 introduced to_string()overloads which are convenient if you have an integral value or two to concatentate with or into a string:

C++11 引入了to_string()重载,如果您有一两个整数值与 a 连接或连接到 a 中,这会很方便string

std::string s = "Number of people is " + std::to_string(numPeople);

This may be inefficient though (check your compiler(s) optimisation abilities if you care): each std::to_string()is likely to dynamically allocate a buffer for an independent std::stringinstance, then the individual concatenations may involve extra copying of text, and the original dynamically-allocated buffers may need to be enlarged, then most of those temporary std::strings will take time to deallocate during destruction.

尽管这可能效率低下(如果您关心,请检查您的编译器优化能力):每个std::to_string()都可能为独立std::string实例动态分配缓冲区,然后各个连接可能涉及额外的文本复制,以及原始动态分配的缓冲区可能需要扩大,那么大多数临时std::strings 将需要时间在销毁期间解除分配。

It was worse in C++03

在 C++03 中情况更糟

C++03 lacked move constructors, so it was necessary to use the std::ostringstream::str()member function on the temporary to get an extra deep-copy of the std::stringwith which to construct the named stringsteam...

C++03 缺少移动构造函数,因此有必要std::ostringstream::str()在临时对象上使用成员函数来获取std::string构造命名stringsteam...的额外深层副本。

stringstream ss(static_cast<std::ostringstream&>(std::ostringstream() << "Number of people is " << numPeople).str());

With this C++03 code, there's a likelihood of duplicate dynamic memory allocations and a copy of content, so construction-followed-by-streaming was a better bet.

使用此 C++03 代码,可能会出现重复的动态内存分配和内容副本,因此构建后流式传输是更好的选择。

回答by dotslashb

The stringbuf has to be initialized before values can be added to it. stringstream is an object.

必须先初始化 stringbuf,然后才能向其添加值。stringstream 是一个对象。

By doing:

通过做:

std::stringstream ss;

You are essentially allowing the application to allocate space to handle the to-be added values.

您实际上是在允许应用程序分配空间来处理要添加的值。