Consider the following function:
void f(const char* str);
Suppose I want to generate a string using stringstream and pass it to this function. If I want to do it in one statement, I might try:
f((std::ostringstream() << "Value: " << 5).str().c_str()); // error
This gives an error: 'str()' is not a member of 'basic_ostream'. OK, so operator<< is returning ostream instead of ostringstream - how about casting it back to an ostringstream?
1) Is this cast safe?
f(static_cast<std::ostringstream&>(std::ostringstream() << "Value: " << 5).str().c_str()); // incorrect output
Now with this, it turns out for the operator<<("Value: ") call, it's actually calling ostream's operator<<(void*) and printing a hex address. This is wrong, I want the text.
2) Why does operator<< on the temporary std::ostringstream() call the ostream operator? Surely the temporary has a type of 'ostringstream' not 'ostream'?
I can cast the temporary to force the correct operator call too!
f(static_cast<std::ostringstream&>(static_cast<std::ostringstream&>(std::ostringstream()) << "Value: " << 5).str().c_str());
This appears to work and passes "Value: 5" to f().
3) Am I relying on undefined behavior now? The casts look unusual.
I'm aware the best alternative is something like this:
std::ostringstream ss;
ss << "Value: " << 5;
f(ss.str().c_str());
...but I'm interested in the behavior of doing it in one line. Suppose someone wanted to make a (dubious) macro:
#define make_temporary_cstr(x) (static_cast<std::ostringstream&>(static_cast<std::ostringstream&>(std::ostringstream()) << x).str().c_str())
// ...
f(make_temporary_cstr("Value: " << 5));
Would this function as expected?
You cannot cast the temporary stream to std::ostringstream&. It is ill-formed (the compiler must tell you that it is wrong). The following can do it, though:
f(static_cast<std::ostringstream&>(
std::ostringstream().seekp(0) << "Value: " << 5).str().c_str());
That of course is ugly. But it shows how it can work. seekp is a member function returning a std::ostream&. Would probably better to write this generally
template<typename T>
struct lval { T t; T &getlval() { return t; } };
f(static_cast<std::ostringstream&>(
lval<std::ostringstream>().getlval() << "Value: " << 5).str().c_str());
The reason that without anything it takes the void*, is because that operator<< is a member-function. The operator<< that takes a char const* is not.
A temporary cannot be passed as a non-const reference to a function, that's why it does not find the correct streaming operator and instead takes the one with void* argument (it is a member function and thus calling it on a temporary is OK).
What comes to getting around the limitations by casting, I have a feeling that it is in fact UB, but I cannot say for sure. Someone else will surely quote the standard.
This can be done using a C++11 lambda function.
#include <iostream>
#include <sstream>
void f(const char * str)
{
std::cout << str << std::endl;
}
std::string str(void (*populate)(std::ostream &))
{
std::ostringstream stream;
populate(stream);
return stream.str();
}
int main(int argc, char * * args)
{
f(str([](std::ostream & ss){ ss << "Value: " << 5; }).c_str());
return 0;
}
// g++ -std=c++11 main.cpp -o main
// ./main
// Value: 5
If you like one_lined statements you can write:
// void f(const char* str);
f(static_cast<ostringstream*>(&(ostringstream() << "Value: " << 5))->str());
However you should prefer easier to maintain code as:
template <typename V>
string NumberValue(V val)
{
ostringstream ss;
ss << "Value: " << val;
return ss.str();
}
f(NumberValue(5));
I use something a bit like this for logging.
#include <sstream>
using namespace std;
const char *log_text(ostringstream &os, ostream &theSame)
{
static string ret; // Static so it persists after the call
ret = os.str();
os.str(""); // Truncate so I can re-use the stream
return ret.c_str();
}
int main(int argc, char **argv)
{
ostringstream ss;
cout << log_text(ss, ss << "My first message") << endl;
cout << log_text(ss, ss << "Another message") << endl;
}
Output:
My first message
Another message
Since C++17 we have folding expressions for templates that can be used to make generic string formatter that can accept everything that have stream support:
template <class... Args>
std::string format(Args &&... args)
{
std::ostringstream ostr;
(ostr << ... << args);
return ostr.str();
}
The you can use it like: format("Int number: ", 42, " Float number: ", 3.14).c_str().
In C++20 std::format is coming.
Related
I'm working on a CGI application, which needs to send response headers, including Content-Length, before the body, but of course this is unknown until the body is fully formed. I could just use a string and concatenate as I go, but I like using the << operator as with cout, so I created this little class:
#include <iostream>
using namespace std;
class outbuf {
public:
void operator<<(const char *str) {
this->buffer+= str;
}
void operator<<(const string &str) {
this->buffer+= str;
}
void obsend() {
cout << this->buffer;
this->buffer.clear();
}
private:
string buffer;
};
int main(int argc, char **argv, char** envp) {
outbuf cbout;
string s = " of the output buffer.";
cbout << "This is ";
cbout << "a test" << " ...";
cbout << s;
cbout.obsend();
return 0;
}
The problem comes with cbout << "a test" << " ..."; On the second operator, the compiler complains invalid operands of types 'void' and 'const char [5]' to binary 'operator<<' I understand the error, but not sure what to do about it. Is there a better way to accomplish what I'm trying to do? This article looked promising, but I'm not able to understand some of what he's talking about, and it doesn't appear to exactly fit what I'm trying to do.
Your operator<< overload should simply return a reference to itself:
outbuf &operator<<(const char *str) {
// ...
return *this;
}
So now the result of the first << operator is the same object, against which the second, chained, << operator will happily use.
Change all your << operators to work this way.
I'm writing a program and I want to be able to cleanly wrap a string in quotes without having to do something like
std::string firstString = "This is a string";
std::string myString = "\"" + firstString + "\"";
So I wrote a couple of template functions to take their arguments and wrap them in quotes. I've also included my first (naive) attempt at writing a general toString() function (I know about to_string, but I'm doing this for learning too).
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <typeinfo>
template <typename T>
std::string toString(const T &convert)
{
std::string returnString{""};
std::stringstream transfer;
transfer << convert;
transfer >> returnString;
return returnString;
}
template<typename T>
std::string tQuoted(const T &convert)
{
std::cout << "Called template overload" << std::endl;
return ("\"" + toString(convert) + "\"");
}
template<typename T>
std::string tQuoted(const std::string &convert)
{
std::cout << "Called std::string overload" << std::endl;
return ("\"" + convert + "\"");
}
template<typename T>
std::string tQuoted(const char *convert)
{
std::cout << "Called const char overload" << std::endl;
return ("\"" + static_cast<std::string>(convert) + "\"");
}
template<typename T>
std::string tQuoted(std::string convert)
{
std::cout << "Called normal std::string overload" << std::endl;
return ("\"" + convert + "\"");
}
template<typename T>
std::string tQuoted(std::string&& convert)
{
std::cout << "Called rvalue std::string overload" << std::endl;
return ("\"" + convert + "\"");
}
int main()
{
std::vector<std::string> my{"Hello", "30 Days Of Coding", "All Work And No Play"};
std::string myString = "Hello, World!";
std::string *strPtr = &myString;
std::string *mySuperPtr = new std::string{"He's a cockaroach"};
for (std::vector<std::string>::const_iterator iter = my.begin(); iter != my.end(); iter++) {
std::cout << tQuoted(*iter) << std::endl;
}
std::cout << tQuoted(myString) << std::endl;
std::cout << tQuoted(*strPtr) << std::endl;
std::cout << tQuoted(mySuperPtr) << std::endl;
std::cout << tQuoted(std::string{"Another string"}) << std::endl;
delete mySuperPtr;
mySuperPtr = nullptr;
return 0;
}
Every one of those calls the template constructor:
Called template overload
"Hello"
Called template overload
"30"
Called template overload
"All"
Called template overload
"Hello,"
Called template overload
"Hello,"
Called template overload
"0x13cad10"
Called template overload
"Another"
Of course, a much less naive toString() method would do basic checking to see if the parameter was a std::string, and just return that if it was. It seems that a std::stringstream will stop when it encounters the first space in a string (hence the truncated output). However, this isn't the main focus of my confusion.
Sorry for the very basic question, but this one really has me stumped. Thanks for any help you can provide.
You are not specializing the template function correctly. This is how to correctly specialize it:
template<>
std::string tQuoted(const std::string &convert)
{
std::cout << "Called std::string overload" << std::endl;
return ("\"" + convert + "\"");
}
Resulting output becomes:
Called std::string overload
"Hello"
Called std::string overload
"30 Days Of Coding"
Called std::string overload
"All Work And No Play"
Called std::string overload
"Hello, World!"
Called std::string overload
"Hello, World!"
Called template overload
"0x1c27d10"
Called std::string overload
"Another string"
Note that for
tQuoted(mySuperPtr)
mySuperPtr is a pointer to a string, and not a string, hence this doesn't use the specialized template function.
Take a careful look at this function template that you wrote:
template<typename T>
std::string tQuoted(const std::string &convert)
{
std::cout << "Called std::string overload" << std::endl;
return ("\"" + convert + "\"");
}
It's a function template, with template parameter T, but where does T come from? It's nowhere. Specifically, it's a non-deduced context. There's no way for the compiler to tell what T is from tQuoted(myString), you'd have to explicitly call tQuoted<X>(myString).
But in this case, you don't actually want T anyway. You're not trying to write a new function template. You're trying to write an overload specifically for std::string (as the body of your function suggests). So just write an overload:
std::string tQuoted(const std::string &convert)
{
std::cout << "Called std::string overload" << std::endl;
return ("\"" + convert + "\"");
}
No template necessary. The same is true of all your other overloads - they are all accidentally function templates with template parameters that are non-deduced contexts.
Avoid function template specializations unless you really, really need them. Which, in this case, you don't. See Why Not Specialize Function Templates?
I am curious if it is possible to overload a << stream operator for a function?
I am using OutputDebugString on windows to write to the log, and it only accepts strings.
I am wondering if I can write a function in c++ where I could wrap OutputDebugString and do the following
MyLogFuntion() << string << int << char;
You can return an object from your function that has operator << and then do the logging in the object's destructor. Then when you call MyLogFunction() it will create a temporary object which will store all the data inserted into it and then output it when the object is goes out of scope at the end of the statement.
Here's an example (without The logger function which is actually redundant)
#include <iostream>
#include <sstream>
class Logger {
std::stringstream ss;
public:
~Logger() {
// You want: OutputDebugString(ss.str());
std::cout<< ss.str();
}
// General for all types supported by stringstream
template<typename T>
Logger& operator<<(const T& arg) {
ss << arg;
return *this;
}
// You can override for specific types
Logger& operator<<(bool b) {
ss << (b? "Yep" : "Nope");
return *this;
}
};
int main() {
Logger() << "Is the answer " << 42 << "? " << true;
}
Output:
Is the answer 42? Yep
You cannot provide overloads in the way you would like to.
If the method you have to use (OutputDebugString in your case) forces you to provide a std::string (or similar) parameter, you'll have to provide that parameter somehow. One way is to use a std::stringstream, stream into that, and then pass the result to OutputDebugString:
std::stringstream ss;
ss << whatever << " you " << want << to << stream;
OutputDebugString(ss.str());
You could also dump this into a macro if you really want things more compact:
#define OUTPUT_DEBUG_STRING(streamdata) \
do { \
std::stringstream ss; \
ss << streamdata; \
} while (0)
And then write
OUTPUT_DEBUG_STRING(whatever << " you " << want << to << stream);
Another alternative is to write a more complex wrapper class around OutputDebugString which provides stream operators. But that is probably not going to be worth the effort.
Is it possible to write a method that takes a stringstream and have it look something like this,
void method(string str)
void printStringStream( StringStream& ss)
{
method(ss.str());
}
And can be called like this
stringstream var;
printStringStream( var << "Text" << intVar << "More text"<<floatvar);
I looked up the << operator and it looks like it returns a ostream& object but I'm probably reading this wrong or just not implementing it right.
Really all I want is a clean way to concatenate stuff together as a string and pass it to a function. The cleanest thing I could find was a stringstream object but that still leaves much to be desired.
Notes:
I can't use much of c++11 answers because I'm running on Visual Studio 2010 (against my will, but still)
I have access to Boost so go nuts with that.
I wouldn't be against a custom method as long as it cleans up this mess.
Edit:
With #Mooing Duck's answer mixed with #PiotrNycz syntax I achieved my goal of written code like this,
try{
//code
}catch(exception e)
{
printStringStream( stringstream() << "An exception has occurred.\n"
<<" Error: " << e.message
<<"\n If this persists please contact "<< contactInfo
<<"\n Sorry for the inconvenience");
}
This is as clean and readable as I could have hoped for.
Hopefully this helps others clean up writing messages.
Ah, took me a minute. Since operator<< is a free function overloaded for all ostream types, it doesn't return a std::stringstream, it returns a std::ostream like you say.
void printStringStream(std::ostream& ss)
Now clearly, general ostreams don't have a .str() member, but they do have a magic way to copy one entire stream to another:
std::cout << ss.rdbuf();
Here's a link to the full code showing that it compiles and runs fine http://ideone.com/DgL5V
EDIT
If you really need a string in the function, I can think of a few solutions:
First, do the streaming seperately:
stringstream var;
var << "Text" << intVar << "More text"<<floatvar;
printStringStream(var);
Second: copy the stream to a string (possible performance issue)
void printStringStream( ostream& t)
{
std::stringstream ss;
ss << t.rdbuf();
method(ss.str());
}
Third: make the other function take a stream too
Make your wrapper over std::stringstream. In this new class you can define whatever operator << you need:
class SSB {
public:
operator std::stringstream& () { return ss; }
template <class T>
SSB& operator << (const T& v) { ss << v; return *this; }
template <class T>
SSB& operator << (const T* v) { ss << v; return *this; }
SSB& operator << (std::ostream& (*v)(std::ostream&)) { ss << v; return *this; }
// Be aware - I am not sure I cover all <<'s
private:
std::stringstream ss;
};
void print(std::stringstream& ss)
{
std::cout << ss.str() << std::endl;
}
int main() {
SSB ssb;
print (ssb << "Hello" << " world in " << 2012 << std::endl);
print (SSB() << "Hello" << " world in " << 2012 << std::endl);
}
For ease of writing objects that can be inserted into a stream, all these classes overload operator<< on ostream&. (Operator overloading can be used by subclasses, if no closer match exists.) These operator<< overloads all return ostream&.
What you can do is make the function take an ostream& and dynamic_cast<> it to stringstream&. If the wrong type is passed in, bad_cast is thrown.
void printStringStream(ostream& os) {
stringstream &ss = dynamic_cast<stringstream&>(os);
cout << ss.str();
}
Note: static_cast<> can be used, it will be faster, but not so bug proof in the case you passed something that is not a stringstream.
Since you know you've got a stringstream, just cast the return value:
stringstream var;
printStringStream(static_cast<stringstream&>(var << whatever));
Just to add to the mix: Personally, I would create a stream which calls whatever function I need to call upon destruction:
#include <sstream>
#include <iostream>
void someFunction(std::string const& value)
{
std::cout << "someFunction(" << value << ")\n";
}
void method(std::string const& value)
{
std::cout << "method(" << value << ")\n";
}
class FunctionStream
: private virtual std::stringbuf
, public std::ostream
{
public:
FunctionStream()
: std::ostream(this)
, d_function(&method)
{
}
FunctionStream(void (*function)(std::string const&))
: std::ostream(this)
, d_function(function)
{
}
~FunctionStream()
{
this->d_function(this->str());
}
private:
void (*d_function)(std::string const&);
};
int main(int ac, char* av[])
{
FunctionStream() << "Hello, world: " << ac;
FunctionStream(&someFunction) << "Goodbye, world: " << ac;
}
It is worth noting that the first object sent to the temporary has to be of a specific set of types, namely one of those, the class std::ostream knows about: Normally, the shift operator takes an std::ostream& as first argument but a temporary cannot be bound to this type. However, there are a number of member operators which, being a member, don't need to bind to a reference! If you want to use a user defined type first, you need to extract a reference temporary which can be done by using one of the member input operators.
#include <string>
#include <iostream>
template <typename T>
T max(T a, T b) {
return a > b ? a : b;
}
class Dummy {
private:
std::string name;
int age;
public:
Dummy(int an_age) {age = an_age;}
bool operator> (Dummy &a) {return age > a.age;}
std::string toString() const {return "The age is " + age;}
};
std::ostream& operator<<(std::ostream& out, const Dummy& d) {return out<< d.toString();}
int main()
{
std::cout << max(3, 7) << std::endl;
std::cout << max(3.0, 7.0) << std::endl;
std::cout << max<int>(3, 7.0) << std::endl;
std::cout << max("hello", "hi") << std::endl;
Dummy d1(10);
Dummy d2(20);
std::cout << max(&d1, &d2) << std::endl;
return 0;
}
I'm pretty new to C++ but not new to programming. I've written the code to play with template and operator overloading in C++.
It took quite a while to make it compile and partially work.
The ostream operator<< is not working properly, only to return the address of the object. I can't figure out the causes.
I managed to make it compile by blind trial and error, so I suspect the code might be broken to some extent. And I may not be aware of what'd be improved.
Your max(&d1,&d2) expression gives you the address, and that is printed out. Your operator overloading is fine.
I assume the line you're talking about is
std::cout << max(&d1, &d2) << std::endl;
The problem is you are passing Dummy * instead of Dummy. That makes max return Dummy *, and since your overloaded operator<< takes (essentially) Dummy, it isn't invoked. If you're trying to pass by reference, you don't need to do anything special on the caller side, just make the function take a reference and the compiler will figure it out.
Don't write your own max, use the standard one instead:
#include <algorithm>
void f() { int a = std::max(8, 4); }
The only difference is that the standard max uses operator < by default, just like everything else in the standard library.
Your toString function does something different from what you think it does. It instead returns the sub string of "The age is " starting at the character number age. For example if age is 3, toString will return " age is ". To convert the integer to string you have to use ostringstream:
std::string toString() const {
std::ostringstream s;
s << "The age is " << age;
return s.str();
}