I have been using the following code to clear std::stringstream
:
m.swap(std::stringstream());
Code probably taken from this SO thread. Recently I compiled my code in Visual Studio 2013 and I received the following warning:
warning C4239: nonstandard extension used : 'argument' : conversion from 'std::basic_stringstream<char,std::char_traits<char>,std::allocator<char>>' to 'std::basic_stringstream<char,std::char_traits<char>,std::allocator<char>> &'
1> A non-const reference may only be bound to an lvalue
I did not receive any warning in earlier versions of Visual Studio using /W4. I recall I had trouble reliably clearing stringstreams in earlier versions which is why I ended up using that code in the first place.
So is it portable to clear a stringstream that way, and if not could you explain why not? Also is there a portable way to clear a stringstream? Thanks
Edit: Here is the code that was requested. Compile it using /W4
to see the warning.
int _tmain(int argc, _TCHAR* argv[])
{
std::stringstream m;
m.swap(std::stringstream());
return 0;
}
Here's the signature of std::stringstream::swap()
:
void swap( basic_stringstream& other );
As you can see, swap()
takes an lvalue-reference to its argument. An rvalue or temporary cannot bind to an lvalue-reference as your compiler is correctly telling you. Some compilers support non-standard extensions that allow you to do this, but I would advise that you stay within the bounds of the standard, it's much safer.
However, while you may not be able to bind the temporary to the lvalue-reference, you can transform the temporary into an lvalue using this std::skipws
trick:
m.swap(static_cast<std::stringstream&>(stringstream{} >> std::skipws));
or even
std::stringstream{}.swap(m):
In the first example, the function operator>>()
returns a reference to the stream, which is safe to use with swap()
because the reference that holds the argument is destroyed at the end of the function.
The std::swap
function takes two non-const parameters to swap. This is because both parameters are changed when the function is called. Similarly, the std::stringstream::swap(...)
function, takes a single non-const parameter to swap with.
For example:
std::vector<int> vec1, vec2;
std::swap(vec1, vec2);
In the above sample, both vec1
and vec2
are altered. When you try to do this...
m.swap(std::stringstream());
... you're trying to assign the contents of the temporary std::stringstream()
with the contents of m
, which to a compiler looks like a bug, even if your intention was simply to clear the contents of m
.
To remove the warning, simply declare a temporary std::stringstream
before performing the swap. Like this:
std::stringstream temp;
m.swap(temp);
That use of swap
is not allowed by the Standard. The declaration is
template <typename CharT, typename Traits, typename Allocator>
void std::basic_stringstream<CharT, Traits, Allocator>::swap(
basic_stringstream& other);
which implies that both stringstream
objects will be modified. But the expression std::stringstream()
is an rvalue (specifically, a temporary), and C++ does not allow binding non-const lvalue references to temporaries, since modifying a temporary is not often the real intent.
The easy solution is:
m = std::stringstream();
But if you need to support compilers without C++11 support, neither will work, since in the C++03 Standard, stringstream
has no swap
function and no public operator=
. In that case, you would need to go with:
m.clear();
m.str(std::string());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With