|
Prev: Nested variable declarations using the same name
Next: A Set of Questions About Console I/O and Structures...
From: Brendan on 24 Apr 2008 06:43 On Apr 23, 12:14 pm, "Niels Dekker - no return address" <nore...(a)this.is.invalid> wrote: > Does the Standard Library support creating an std::string by means of > streaming, without having to declare a *named* ostringstream object? I tried > the following: > > #include <sstream> > #include <string> > int i = 42; > > std::string s = (std::ostringstream() << "i = " << i).str(); > > Of course it didn't compile, because a temporary (std::ostringstream()) cannot > be passed as non-const reference to a function (operator<<). Okay, second > try, wrapping the ostringstream as follows: > > template <typename T> class Wrapper { > T m_data; > public: > T & get() { > return m_data; > } > }; > > std::string s = (Wrapper<std::ostringstream>().get() << "i = " << i).str(); > > Unfortunately it still didn't compile, because operator<< returns an > std::basic_ostream, instead of an std::ostringstream, and therefore it doesn't > have an str() member function. Now I wonder, is it safe to cast the stream, > returned by operator<< to an ostringstream reference? As follows: > > std::string s = > static_cast<std::ostringstream&>(Wrapper<std::ostringstream>().get() > << "i = " << i).str(); > > At least, it *seems* to work... But is it the proper way to do it? I actually like your workaround, although you should typedef Wrapper<std::ostringstream> to make it cleaner. I believe that temporaries are guaranteed to stick around until the next statement, so you are good. Oh! also, overload << something like this: std::string operator<<(basic_ostream& stream, ToStr& tstr) { return static_cast<std::ostringstream&>(stream).str(); } I haven't tested that, and obviously it isn't type safe, but since << is left associative you should be able to: string x = temp_ostringstream().get() << "i = " << i << to_str; where to_str is the single instance of ToStr. Pretty nifty eh? There's probably some way to make getting the temporary ostringstream easier, and maybe even making this statically type safe, but it's late... iostreams << are pretty lame for formatting syntactically speaking and pretty much everybody ends up rolling their own formatting utility on top of it. Check out: http://www.boost.org/doc/libs/1_35_0/libs/format/doc/format.html which is basically a typesafe printf. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: guinness.tony on 7 May 2008 02:43 On 2 May, 19:45, "Niels Dekker - no return address" <nore...(a)this.is.invalid> wrote: > Tony (aka "Guinness Tony") wrote: <snip> > > // partial specializationss > > template<class traits> > > basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, > ... > > > [how odd - I've never noticed that "specializationss" typo before!] > > Actually those overloaded operator<< functions aren't even template > specializations! In 2001 it was already noticed by Andy Sawyer: LWG issue 311 > "Incorrect wording in basic_ostream class synopsis"http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#311 Indeed, but that resolution didn't seem to make it into the 2003 revised standard (from which I quoted the declarations.) <snip> > Interesting!!! That could be a source of very nasty bugs, especially when > switching from one library implementation to another! All library implementations should follow the standard and thus behave in a consistent (if surprising) manner. Some pre-standard libraries implemented the (char const*) inserters as members, but surely we are talking about standards-conformant implementations, here? Even the still-all-too-popular MSVC++6's library implements them as non-members (although the compiler silently permits binding of temporaries to non-const references, so int i = 42; std::string s = static_cast<std::ostringstream&>( std::ostringstream() << "i = " << i).str(); ....actually works with that compiler, producing the "expected" result, for all the wrong reasons!) > Still, why do you think the "flush trick" is superior to creating a > "temporary" lvalue by means of a wrapper? Sorry - I didn't mean to claim superiority; I just wanted to add an alternative solution to the mix. > Do you have any references, showing > that the "flush trick" is indeed a well-known idiom? Well, I recall having first encountered it in a discussion in one of the clc++/clc++m newsgroups, presented by one of the regulars. After a bit of searching, I've finally discovered that thread: http://groups.google.co.uk/group/comp.lang.c++.moderated/browse_thread/thread/28f0226f8809eff5/ To my chagrin, I see now that Alf introduced it as "a nasty trick" and James questioned whether it is a "clean" solution. How my memory plays tricks! "Idiomatic" is certainly not a description of this technique and I retract my use of that term. "A curiosity" is probably nearer the mark. > (I wonder how many > people actually /know/ that std::flush is inserted by a member function, while > other objects, e.g., strings, are inserted by non-member functions.) Alf's original presentation of this method actually used the ostream::flush() member function (why didn't I remember it that way?), so knowledge of how std::flush() is inserted becomes moot. > Otherwise I think I'll stick to the wrapper... I think that's probably for the best! Regards, Tony. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
First
|
Prev
|
Pages: 1 2 Prev: Nested variable declarations using the same name Next: A Set of Questions About Console I/O and Structures... |