I would like to be able to do:
foo(stringstream()<<"number = " << 500);
EDIT: single line solution is crucial since this is for logging purposes. These will be all around the code.
inside foo will print the string to screen or something of the sort.
now since stringstream's operator<< returns ostream&, foo's signature must be:
foo(ostream& o);
but how can I convert ostream& to string? (or char*).
Different approaches to achieving this use case are welcome as well.
The obvious solution is to use dynamic_cast in foo. But the given
code still won't work. (Your example will compile, but it won't do what
you think it should.) The expression std::ostringstream() is a
temporary, you can't initialize a non-const reference with a temporary,
and the first argument of std::operator<<( std::ostream&, char const*)
is a non-const reference. (You can call a member function on a
temporary. Like std::ostream::operator<<( void const* ). So the code
will compile, but it won't do what you expect.
You can work around this problem, using something like:
foo( std::ostringstream().flush() << "number = " << 500 );
std::ostream::flush() returns a non-const reference, so there are no
further problems. And on a freshly created stream, it is a no-op.
Still, I think you'll agree that it isn't the most elegant or intuitive
solution.
What I usually do in such cases is create a wrapper class, which
contains it's own std::ostringstream, and provides a templated
member operator<< which forwards to the contained
std::ostringstream. Your function foo would take a const
reference to this—or what I offen do is have the destructor call
foo directly, so that the client code doesn't even have to worry about
it; it does something like:
log() << "number = " << 500;
The function log() returns an instance of the wrapper class (but see
below), and the (final) destructor of this class calls your function
foo.
There is one slight problem with this. The return value may be copied,
and destructed immediately after the copy. Which will wreck havoc with
what I just explained; in fact, since std::ostringstream isn't
copyable, it won't even compile. The solution here is to put all of the
actual logic, including the instance of std::ostringstream and the
destructor logic calling foo in a separate implementation class, have
the public wrapper have a boost::shared_ptr to it, and forward. Or
just reimplement a bit of the shared pointer logic in your class:
class LogWrapper
{
std::ostringstream* collector;
int* useCount;
public:
LogWrapper()
: collector(new std::ostringstream)
, useCount(new int(1))
{
}
~LogWrapper()
{
-- *useCount;
if ( *useCount == 0 ) {
foo( collector->str() );
delete collector;
delete useCount;
}
}
template<typename T>
LogWrapper& operator<<( T const& value )
{
(*collector) << value;
return *this;
}
};
Note that it's easy to extend this to support optional logging; just
provide a constructor for the LogWrapper which sets collector to
NULL, and test for this in the operator<<.
EDITED:
One other thing occurs to me: you'll probably want to check whether the
destructor is being called as a result of an exception, and not call
foo in that case. Logically, I'd hope that the only exception you
might get is std::bad_alloc, but there will always be a user who
writes something like:
log() << a + b;
where the + is a user defined overload which throws.
I would suggest you to use this utility struct:
struct stringbuilder
{
std::stringstream ss;
template<typename T>
stringbuilder & operator << (const T &data)
{
ss << data;
return *this;
}
operator std::string() { return ss.str(); }
};
And use it as:
void f(const std::string & s );
int main()
{
char const *const pc = "hello";
f(stringbuilder() << '{' << pc << '}' );
//this is my most favorite line
std::string s = stringbuilder() << 25 << " is greater than " << 5 ;
}
Demo (with few more example) : http://ideone.com/J995r
More on my blog : Create string on the fly just in one line
You could use a proxy object for this; this is a bit of framework, but if you want to use this notation in a lot of places then it may be worth it:
#include <iostream>
#include <sstream>
static void foo( std::string const &s )
{
std::cout << s << std::endl;
}
struct StreamProxy
{
std::stringstream stream;
operator std::string() { return stream.str(); }
};
template <typename T>
StreamProxy &operator<<( StreamProxy &s, T v )
{
s.stream << v;
return s;
}
static StreamProxy make_stream()
{
return StreamProxy();
}
int main()
{
foo( make_stream() << "number = " << 500 );
}
This program prints
number = 500
The idea is to have a little wrapper class which can be implicitely converted into a std::string. The << operator is simply forwarded to the contained std::stringstream. The make_stream() function is strictly speaking not necessary (you could also say StreamProxy(), but I thought it looks a bit nicer.
A couple of options other than the nice proxy solution just presented by Frerich Raabe:
Define a static string stream variable in the header that defines the logging function and use the comma operator in your invocation of the logging function so that this variable is passed rather than the ostream& returned by the stream insertion operator. You can use a logging macro to hide this ugliness. The problem with this solution is that it is a bit on the ugly side, but this is a commonly used approach to logging.
Don't use C++ I/O. Use a varargs C-style solution instead. Pass a format string as the first argument, with the remaining arguments being targets for that format string. A problem with this solution is that even if your compiler is smart enough to ensure that printf and its cousins are safe, the compiler probably won't know that this new function is a part of the printf family. Nonetheless, this is also a commonly used approach.
If you don't mind using macros functions, you can make the logging function accept const string&, and use the following macro
#define build_string(expr) \
(static_cast<ostringstream*>(&(ostringstream().flush() << expr))->str())
And suppose you foo has signature void foo(const string&), you only need the one-liner
foo(build_string("number = " << 500))
This was inspired by James Kanze's answer about static_cast and stringstream.flush. Without the .flush() the above method fails with unexpected output.
Please note that this method should not leak memory, as temporary values, whether in the pointer form or not, are still allocated on the stack and hence destroyed upon return.
Since you're converting to string anyways, why not
void foo(const std::string& s)
{
std::cout << "foo: " << s << std::endl;
}
...
std::stringstream ss;
ss << "number = " << 500;
foo(ss.str());
This is not possible. As the name ostream implies, it is used for output, for writing to it. You could change the parameter to stringstream&. This class has the method str() which returns a std::string for your use.
EDIT I did not read the issue with operator << returning ostream&. So I guess you cannot simply write your statements within the functions argument list but have to write it before.
You can create a small wrapper around std::ostringstream that will convert back to std::string on use, and have the function take a std::string const &. The first approach to this solution can be found in this answer to a different question.
On top of that, you can add support for manipulators (std::hex) if needed.
Related
I'd like to understand why writing this
static_cast<std::ostringstream*>( &(std::ostringstream() << speed.x) )->str();
makes a string, but not this
(std::ostringstream() << speed.x).str();?
in fact the latter doesn't even compile...
I find this static_cast<foo*>&foo to be quite weird.
can you give me good examples in which case it's good practice to do so?
The the expression std::ostringstream() << speed.x actually invokes the operator<<(double) on the underlying base class std::ostream interface.
The return type of std::ostream::operator<<(double) is std::ostream& which means you're trying to invoke the member function std::ostream::str() which of course does not exist. That method is on the derived class.
This is why the static_cast is necessary in this use case.
You could also write:
static_cast<std::ostringstream&>(std::ostringstream() << speed.x).str();
or since c++11
std::to_string(speed.x);
or in previous versions, you could write your own, less cryptic function which will do the same thing in a more maintainable way with no overhead.
std::string to_string(double x)
{
std::ostringstream ss;
ss << x;
return ss.str();
}
This works:
stringstream temp;
temp << i;
result_stream << transform(temp.str());
(transform is a function that takes a string and returns a string; i is an int). However, my attempt to let C++11 create a temporary object without a name didn't work:
result_stream << transform((stringstream() << i).str());
I thought it would work, since the second << should just return the first argument and I'd be able to use str() on that. But I get this error:
error: 'class std::basic_ostream<char>' has no member named 'str'
I'm using g++ 4.8.1 (MinGW-W64).
Is there a way to accomplish this (i.e. write code like this using an unnamed temporary)? (The above code is a bit simplified, and the actual code involves using << on arguments other than int.)
This doesn't work because the second << is std::ostream &operator<<(std::ostream &, int); and so the return type is ostream& which has no member str().
You would have to write:
result_stream << transform( static_cast<stringstream &>(stringstream() << i).str() );
Update (2019): According to LWG 1203 the standard may be changed in future (and one major implementation already has) so that this code no longer works, and a simpler code works instead. See this question for detail.
In the interim period, apparently the following works on both old and new:
result_stream << transform( static_cast<stringstream &>(stringstream().flush() << i).str() );
// ^^^^^^^^
This should not be a performance penalty since flushing an empty stream has no effect...
operator<<() returns a reference to the base class std::ostream contained within the std::stringstream. The base class doesn't contain the str() method. You can cast it back down to a std::stringstream&:
result_stream << transform(static_cast<std::stringstream&>(std::stringstream() << i).str());
The result of the << operator on the temporary stringstream is an ostream. There is no str() method on an ostream.
Use to_string instead:
using std::to_string;
result_stream << transform(to_string(i));
You can define a helper to_string to handle objects not covered by std::to_string.
template <typename T>
std::string to_string (const T &t) {
std::ostringstream oss;
oss << t;
return oss.str();
}
For example, if you had a class Foo that understood redirection to an ostream, and f was an instance of Foo, then you could do:
result_stream << transform(to_string(f));
Try it online!
If you actually want to use a lot of redirection to build up a string before transforming, you could create a helper object for that as well.
struct to_string_stream {
std::ostringstream oss;
template <typename T>
auto & operator << (const T &t) { oss << t; return *this; }
operator std::string () const { return oss.str(); }
void clear () { oss.string(std::string()); }
};
Then, you could do something like:
to_string_stream tss;
result_stream << transform(tss << i << ':' << f);
Try it online!
Tried and failed to do this for C++11 (in 2009):
http://cplusplus.github.io/LWG/lwg-active.html#1203
libc++ went outlaw and implemented it anyway.
It is up for reconsideration, but can not possibly be standardized prior to 2017 (standardization is a glacial process).
I'm trying to port my own code from VS2012 to g++4.8.
I'm getting this compliation error:
AllocationManager.cpp: In member function ‘void AllocationManager::printMemoryLeaks()’:
TRLogger.h:247:42: error: ‘streamAggrator’ was not declared in this scope
#define TRLOG_INFO streamAggrator(logINFO) << PACKET_DESCRIPTION << __FUNCTION__ << ":" << __LINE__ << ": "
^
AllocationManager.cpp:39:2: note: in expansion of macro ‘TRLOG_INFO’
TRLOG_INFO << "sdfs\n";
Where printMemoryLeaks is a dummy function (AllocationManager is not templated):
void AllocationManager::printMemoryLeaks(void)
{
TRLOG_INFO << "sdfs\n";
}
In the file TRLogger.h:
enum TLogLevel {logERROR, logWARNING, logINFO, logDEBUG, logDEBUG1, logDEBUG2, logDEBUG3, logDEBUG4};
class streamAggrator
{
public:
streamAggrator(TLogLevel logLevel);
/* private: */
FILELog fLog;
WarnLog wlog;
std::ostringstream& s1;
std::ostringstream& s2;
};
template<typename T>
streamAggrator& operator<<(streamAggrator& agg, const T& obj)
{
agg.s1 << obj;
agg.s2 << obj;
agg.s2.flush();
return agg;
}
....
#define TRLOG_INFO streamAggrator(logINFO) << PACKET_DESCRIPTION << __FUNCTION__ << ":" << __LINE__ << ": "
How can I solve this function - I didn't find any place that I can use this or using to help the compiler.
Thanks,
Guy
Your immediate problem is that you try to pass a temporary streamAggrator object to a function which takes a streamAggrator by non-const reference. You can't bind temporary object to non-const references. The work-around for this problem is to make the output operator member of your streamAggrator: while you cannot bind a temporary to a non-const reference, you can call non-const member functions. Note that you'll also get problems with maniputors like std::flush (the issue there is that these are templates themselves and you actually need to a concrete operator to call them with to have the compiler deduce their template arguments).
Clearly, I would solve the problem properly, i.e., instead of trying to dig about an attempt to a solution which doesn't create a stream, I would create a std::streambuf do do the actual work. Your examples doesn't do anything useful, i.e., I can't really tell what you are trying to do but the code looks remarkably like trying to do something like teestream: write once but send the output to multiple destintations. I have posted corresponding stream buffers quite a few times in the post (mostly on Usenet, though, but I think, at least, once on Stackoverflow, too).
Although I don't know how to get rid of the macro to fill in the __FILE__ and the __LINE__, the actual stream formatting should probably use a stream buffer:
struct teebuf: std::streambuf {
private:
std::streambuf* sb1;
std::streambuf* sb2;
public:
teebuf(std::streambuf* sb1, std::streambuf* sb2): sb1(sb1), sb2(sb2) {}
int overflow(int c) {
this->sb1->sputc(c);
this->sb2->sputc(c);
return std::char_traits<char>::not_eof(c);
}
int sync() {
this->sb1->pubsync();
this->sb2->pubsync();
}
};
class logstream
: std::ostream {
std::ofstream out;
teebuf sbuf;
public:
logstream()
: out("file.log")
, sbuf(out.rdbuf(), std::clog.rdbuf()) {
this->init(&this->sbuf);
}
logstream(logstream&& other)
: out(std::move(other.out))
, sbuf(std::move(other.sbuf)) {
this->init(&this->sbuf);
};
I think you can return the log stream. I don't know what your logging level is meant to do but I guess its processing was removed while preparing the question: it is probably necessary to change the implementation to take the logging level suitably into account.
I have stumbled upon an error for which I cannot grasp the reason.
I think it basically gets down to this error:
error: no matching function for call to ‘std::basic_ostream<char>::operator<<(const std::basic_string<char>&)’
I looked into specification on www.cplusplus.com and indeed it says there is no definition for std::ostream::operator<< with std::string as an argument.
My question is, what happens when one writes std_ostream_instance << std_fancy_string;. I believe it is one of the most common invocations ( e.g. std::out << std::string("Hello world!") ) next to const char*.
The error originates from these lines:
template<typename T>
void Log::_log(const T& msg)
{ _sink->operator<<( msg ); }
_sink is defied as std::ostream*
There are some wrapping functions around but it breaks here.
I think I could work around by writing
template<>
void Log::_log<std::string>(const std::string& msg) {
_sink->operator<<( msg.c_str() );
}
since there is ostream& operator<< (ostream& out, const unsigned char* s ); defined by default.
I just see no reason why it is not guessed automatically since it clearly works in simple use like cout << any_std_string.
Not sure if this is relevant but I want to be able to pass down through my log functions anything than can be handled by std::ostream. I used explicit non-templated declarations but decided to move to template for log(const T& anything_to_log) to refacator it. It seemed plain stupid to have 5+ overloads. I get the error when I try compiling something like Log::log( std::string("test case") ).
It looks like something stupid-simple but I cannot get it on my own. Tried to google and search stack to no avail.
With regards, luk32.
PS. I checked the work-around and it works. Why it's not implicitly done ?
operator << overloads are not members of ostream. They are freestanding functions, for example
ostream& operator << ( ostream& out, const basic_string<T>& bs );
Try
template<typename T>
void Log::_log(const T& msg)
{ *_sink << msg; }
The std::string version is not a member function, so can't be called as a member of _sink. Try it this way to pick up both member and non-member versions (in fact it is unlikely you will need the member versions at all anyway):
#include <iostream>
#include <string>
int main()
{
std::ostream * os = &std::cout;
std::string s = "Hello\n";
// This will not work
// os->operator<<(s);
(*os) << s;
return 0;
}
Or better yet would be to store _sink as a reference, and output exactly as you normally would to cout.
I'm creating a logger with the following sections:
// #define LOG(x) // for release mode
#define LOG(x) log(x)
log(const string& str);
log(const ostream& str);
With the idea to do:
LOG("Test");
LOG(string("Testing") + " 123");
stringstream s;
LOG(s << "Testing" << 1 << "two" << 3);
This all works as intended, but when I do:
LOG(stringstream() << "Testing" << 1 << "two" << 3);
It does not work:
void log(const ostream& os)
{
std::streambuf* buf = os.rdbuf();
if( buf && typeid(*buf) == typeid(std::stringbuf) )
{
const std::string& format = dynamic_cast<std::stringbuf&>(*buf).str();
cout << format << endl;
}
}
results in 'format' containing junk data instead of the usual correct string.
I think this is because the temporary ostream returned by the << operator outlives the stringstream it comes from.
Or am I wrong?
(Why does string() work in this way? Is it because it returns a reference to itself? I'm assuming yes.)
I would really like to do it this way as I would be eliminating an additional allocation when logging in release mode.
Any pointers or tricks to get it done this way would be welcomed. In my actual solution I have many different log functions and they are all more complex than this. So I would prefer to have this implemented somehow in the calling code. (And not by modifying my #define if possible)
Just to give an idea, an example of one of my actual #defines:
#define LOG_DEBUG_MSG(format, ...) \
LogMessage(DEBUG_TYPE, const char* filepos, sizeof( __QUOTE__( #__VA_ARGS__ )), \
format, __VA_ARGS__)
which matches varargs printf-like log functions taking char*, string() and ostream() as well as non-vararg functions taking string(), exception() and HRESULT.
I think I see what's happening. This produces the expected output:
log(std::stringstream() << 1 << "hello");
while this does not:
log(std::stringstream() << "hello" << 1);
(it writes a hex number, followed by the "1" digit)
A few elements for the explanation:
An rvalue cannot be bound to a non-const reference
It is OK to invoke member functions on a temporary
std::ostream has a member operator<<(void*)
std::ostream has a member operator<<(int)
For char* the operator is not a member, it is operator<<(std::ostream&, const char*)
In the code above, std::stringstream() creates a temporary (an rvalue). Its lifetime is not problematic, as it must last for the whole full expression it is declared into (i.e, until the call to log() returns).
In the first example, everything works ok because the member operator<<(int) is first called, and then the reference returned can be passed to operator<<(ostream&, const char*)
In the second example, operator<<(cannot be called with "std::stringstream()" as a 1st argument, as this would require it to be bound to a non-const reference. However, the member operator<<(void*) is ok, as it is a member.
By the way: Why not define the log() function as:
void log(const std::ostream& os)
{
std::cout << os.rdbuf() << std::endl;
}
Alter your LOG() macro to this:
#define LOG(x) do { std::stringstream s; s << x; log(s.str()); } while(0)
That will let you use the following syntax in your debugging logs, so you don't have to manually construct the string stream.
LOG("Testing" << 1 << "two" << 3);
Then define it to nothing for release, and you'll have no extra allocations.