Can I use an std::ostream to print into a given buffer? - c++

I have a given buffer of characters (maybe even the buffer backing an std::string, but never mind that). I want to print into that buffer using an std::ostream, i.e. I want to be able to write:
span<char> my_buffer = get_buffer();
auto my_os = /* magic */;
static_assert(
std::is_base_of<std::basic_ostream<char>,decltype(my_os)>::value,
"magic failed");
my_os << "hello" << ',' << 123 << '\0';
std::cout << my_buffer << '\n';
and get:
hello,123
on the standard output.
Note: C++11 if possible, and please mention the language standard you're using. (And yes, I know C++11 doesn't have spans.)

(Thank #BoP and #T.C. for the two parts of this solution)
This can be done... if you're willing to use a deprecated C++ construct: std:ostrstream.
#include <strstream>
#include <iostream>
int main() {
const size_t n = 20;
char my_buffer[n];
std::ostrstream my_os(my_buffer, n);
my_os << "hello" << ',' << 123 << '\0';
std::cout << my_buffer << '\n';
}
Notes about this code:
It works (GodBolt)
It is valid C++98! ... of course I had to let go of std::span, auto type inference etc. It's also valid C++11 and later standards.
This will construct an std::strstreambuf, which is what an std::ostrstream uses directly, from your buffer of chars.
(see this on GodBolt)
Unfortunately, with the deprecation of std::ostrstream, we were left with no fully-valid alternative up to, and including, C++20. You would need to implement a custom std::basic_streambuf, and assign it to an std::ostream. :-(
But in C++23 - you are luck! The standard library does offer exactly what you asked for: std::spanstream: A std::ostream backed by a span of char's which it is given at construction.

Related

How to concat string and float

I have a simple variable:
float t = 30.2f;
How do I add it to a string?
char* g = "Temperature is " + h?
Any guaranteed way (I don't have Boost for instance, and unsure of what version of c++ I have) I can get this to work on a microcontroller?
For simple cases, you can just use the std::string class and the std::to_string function, which have both been part of C++ for a long time.
#include <string>
#include <iostream>
int main()
{
float t = 30.2;
std::string r = "Temperature is " + std::to_string(t);
std::cout << r;
}
However, std::to_string doesn't give you much control over the formatting, so if you need to specify a field width or a number of digits after the decimal point or something like that, it would be better to see lorro's answer.
If you have an incomplete implementation of the C++ standard library on your microcontroller so you can't use the functions above, or maybe you just want to avoid dynamic memory allocation, try this code (which is valid in C or C++):
float t = 30.2;
char buffer[80];
sprintf(buffer, "Temperature is %f.", t);
Note that buffer must be large enough to guarantee there will never be a buffer overflow, and failing to make it large enough could cause crashes and security issues.
std::ostringstream oss;
oss << t;
std::string s = "Temperature is " + oss.str();
Then you can use either the string or the c_str() of it (as const char*).
If, for some reason, you don't have standard library, you can also use snprintf() et. al. (printf-variants), but then you need to do the buffer management yourself.
For the sake of completeness, C++20 introduces std::format for fluent string formatting of this sort:
#include <format>
#include <iostream>
#include <string>
int main() {
float t = 30.2f;
std::string s = std::format("Temperature is {}!\n", t);
std::cout << s;
}
Do note that compiler support for the format library is still underway. GCC does not yet support it, and Clang only has experimental support1 in 14.0+.
1 requires LLVM to be compiled with -DLIBCXX_ENABLE_INCOMPLETE_FEATURES=ON

Assigning a number to std::string is now allowed?

Consider the following code snippet:
#include <iostream>
int main() {
std::string foo;
foo = -1; // why is the compiler not complaining about this?
std::cout << "1" << std::endl;
std::cout << foo << std::endl;
std::cout << "2" << std::endl;
}
Actual output (both ideone.com C++14 mode and GCC 4.8.4):
<no output>
Questions:
Why did the code snippet compile at all?
Commenting out foo = -1, I get the correct stdout (1 and 2). What has the compiler compiled with foo = -1; that causes the subsequent couts to fail?
foo = -1;
resolves to std::string::operator=(char) since -1 is an int and int can, in theory, be converted to a char.
It's not clear to me what the standard says when the int does not represent a valid char. It looks like in your implementation, the program crashes.
Update
From the C++11 Standard (emphasis mine):
3.9.1 Fundamental types
1 Objects declared as characters (char) shall be large enough to store any member of the implementation’s basic character set. If a character from this set is stored in a character object, the integral value of that character
object is equal to the value of the single character literal form of that character. It is implementation-defined whether a char object can hold negative values.
It appears that you'll have to consult your compiler's documentation to understand whether it allows char object to hold negative values and, if it does, how does it treat such objects.
char is an integral type in C++. std::string defines an assignment operator:
std::string& operator=(char);
Since int converts to char freely in this context, no diagnostic is given. (It's funny how best intentions pave the road to Hell, innit?)
Since (char)-1 is probably not a valid member if the execution character set on your platform, the stream enters an error state and will stay there, outputting nothing, until the error bit is cleared.
EDIT this is a bug of ideone. If the output stream contains an "illegal" character, the entire stream is not shown, even the parts produced and flushed before the bad character. Use another online compiler to check.
These are the operator= overloads for the string class :-
basic_string& operator=(const basic_string& str);
basic_string& operator=(basic_string&& str) noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value || allocator_traits<Allocator>::is_always_equal::value);
basic_string& operator=(const charT* s);
basic_string& operator=(charT c);
basic_string& operator=(initializer_list<charT>);
Hope that makes sense why that compiled fine.
Now coming onto your question as to why there is no output. I have tweaked the code a little :-
#include <iostream>
int main() {
std::string foo;
foo = -1; // why is the compiler not complaining about this?
char ch = 65;
std::cout << "1" << std::endl;
std::cout << foo << std::endl;
std::cout << ch << std::endl;
//change ch to -1 ... ascii
ch = -1;
std::cout << ch << std::endl;
std::cout << "2" << std::endl;
}
Can you guess what the output is ? Yup think in terms of ascii :-
1
 
A
 
2
That's exactly the reason why you don't have the output for -1.
Compiler - MinGW - std=c++14 -- not sure why IDEONE messes up the complete output stream in your case.

What's the difference between std::to_string, boost::to_string, and boost::lexical_cast<std::string>?

What's the purpose of boost::to_string (found in boost/exception/to_string.hpp) and how does it differ from boost::lexical_cast<std::string> and std::to_string?
std::to_string, available since C++11, works on fundamental numeric types specifically. It also has a std::to_wstring variant.
It is designed to produce the same results that sprintf would.
You may choose this form to avoid dependencies on external libraries/headers.
The throw-on-failure function boost::lexical_cast<std::string> and its non-throwing cousin boost::conversion::try_lexical_convert work on any type that can be inserted into a std::ostream, including types from other libraries or your own code.
Optimized specializations exist for common types, with the generic form resembling:
template< typename OutType, typename InType >
OutType lexical_cast( const InType & input )
{
// Insert parameter to an iostream
std::stringstream temp_stream;
temp_stream << input;
// Extract output type from the same iostream
OutType output;
temp_stream >> output;
return output;
}
You may choose this form to leverage greater flexibility of input types in generic functions, or to produce a std::string from a type that you know isn't a fundamental numeric type.
boost::to_string isn't directly documented, and seems to be for internal use primarily. Its functionality behaves like lexical_cast<std::string>, not std::to_string.
There are more differences: boost::lexical_cast works a bit different when converting double to string. Please consider the following code:
#include <limits>
#include <iostream>
#include "boost/lexical_cast.hpp"
int main()
{
double maxDouble = std::numeric_limits<double>::max();
std::string str(std::to_string(maxDouble));
std::cout << "std::to_string(" << maxDouble << ") == " << str << std::endl;
std::cout << "boost::lexical_cast<std::string>(" << maxDouble << ") == "
<< boost::lexical_cast<std::string>(maxDouble) << std::endl;
return 0;
}
Results
$ ./to_string
std::to_string(1.79769e+308) == 179769313486231570814527423731704356798070600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000
boost::lexical_cast<std::string>(1.79769e+308) == 1.7976931348623157e+308
As you can see, the boost version uses exponential notation (1.7976931348623157e+308) whereas std::to_string prints every digit, and six decimal places. One may be more useful than another for your purposes. I personally find the boost version more readable.
Here is a benchmark that I found for the integer to string conversion, hope it doesn't change much for float and double Fast integer to string conversion benchmark in C++.

Printing Stringstream Outputs Pointer

Rather than outputting the expected string of "Bar", the following code outputs what looks to be a pointer.
#include <sstream>
#include <iostream>
int main()
{
std::stringstream Foo("Bar");
std::cout << Foo << std::endl; // Outputs "0x22fe80."
return 0;
}
This can be worked around by using Foo.str(), but it's caused some issues for me in the past. What causes this strange behavior? Where is it documented?
This can be worked around by using Foo.str(), but it's caused some issues for me in the past. What causes this strange behavior? Where is it documented?
It's not strange at all.
A stream is a stream, not a string.
You can obtain the [string] buffer with the member function .str(). That's not a workaround: it's the API. It should be documented in your C++ standard library reference, and if it's not then your reference is incomplete/wrong.
(What is slightly strange is that you get a memory address rather than a compilation error; that is due to the use of the safe bool idiom in the pre-C++0x standard library, as covered in another answer.)
A std::stringstream is not supposed to be inserted in a stream. That's why you have the str() method.
The behavior you're observing is due to the fact that std::stringstream has a conversion to void*, which is what is used to test the stream:
if(Foo) { // this uses the conversion to void*
}
In C++11, this conversion is replaced by an explicit conversion to bool, which causes this code not to compile:
std::cout << Foo << std::endl;
(1)use std::cout << Foo << std::endl; you should make sure stringstream has already overload "<<".
(2)if there is not overload "<<" , use std::cout << Foo << std::endl; may output the Foo's address.

How can I get the same strstream functionality now that's deprecated?

I use to write code like this:
void fun(char *buff, unsigned size)
{
std::strstream str(buff, size);
str << "hello world: " << 5;
}
so I can use stream output over an arbitrary buffer. I've found this technique both efficient (no allocations) and useful (streams!). Now that std::strstream is deprecated, how can I get the same speed+flexibility that I can get with this code?
The standard library doesn't provide that functionality. However, Boost does with its generic streams and array sources/sinks.
Boost Generic Stream
Boost Array Devices
char buff[size];
boost::stream<boost::array_sink> out(buff, size);
out << "Hello, world!";
(Code untested)
try:
#include <sstream>
std::stringstream str;
str << "hello world: " << 5;
Edit: Sorry, I think I over simplified your question. That functionality is one of the things removed when changing to sstream. Here is something similar (I think this works...):
#include <sstream>
void fun(char *buff, unsigned size)
{
std::stringstream str;
str << "hello world: " << 5;
memcpy(buff, str.str().c_str(), size);
}
Now that std::strstream is deprecated,
how can I get the same
speed+flexibility that I can get with
this code?
I think it was deprecated for a reason. I had numerous portability problems in past when dealing with case of stream reaching the end of the buffer. Lack of the unity probably triggered the deprecation in favor std::string using version.
Otherwise, it amuses me that you mention "speed" in context of iostreams and the "<<" operators. I did bunch of tests in past and iostreams simply cannot catch up with good ol' snprintf(). Making a function call for every element - the effect of "<<" operators - is taxing anyhow you look at it and would be always slower. That's the cost of strict type checks.