473,480 Members | 1,833 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

Problem with one-liner string conversion

Hi,

A few months back I remember reading through C++ newsgroups trying
to find a way to quickly convert a number to a C++ std::string. I
often see code like:

// Create a string that holds a number:
int num = 7; // for example
char tmp[24];
sprintf(tmp, "%d", num);
const std::string str = tmp;

but I wanted to see if there was a better way. I generally would use
this:

// Create a string that holds a number:
int num = 7;
std::ostringstream outStream; // #include <sstream>
outStream << num;
const std::string str = outStream.str();

and this works great, but just like the first example, it declares and
uses a temporary variable/object. What I'd have liked to see was some
sort of method in std::string that handled the conversion in one line,
like this:

// NOTE: not real code!
int num = 7;
const std::string str = std::string::number(num);

While I didn't find what I was looking for, I did find an
interesting post, where someone posted this nice, simple function:

// Converts many things to a std::string:
#include <sstream>

template <typename T>
std::string toStdString(const T &thing)
{
std::ostringstream os;
os << thing;
return os.str();
}

Using this function, I can now write code like this:

int num = 7;
const std::string str = toStdString(num);

This code is very clear, but it also has another benefit: Not only
can I easily convert integers and floats to a std::string, but I can
convert pretty much anything that I can send to std::cout.

But then I thought of something: Why even define a templated
function? I could write code like this:

int num = 7;
std::string str = (std::ostringstream() << num).str();

It may not be as elegant as the toStdString() solution, but at least
it won't require me to define (or include a header file of) the
toStdString() function in every program I write. In addition, there's
no need to introduce a temporary variable to the current scope.

However, when I tried to compile this code, I got the following
error message:

testfile.cpp: In function `int main(int, char**)':
testfile.cpp:23: error: 'struct std::basic_ostream<char,
std::char_traits<char' has no member named 'str'

I can't figure out why I'm getting this error message. I mean, I'm
declaring a std::ostringstream object, using the "<<" operator on it
(which, I believe, returns the very same std::ostringstream object),
and then I call the ::str() method on it. std::ostringstream HAS to
have ::str() defined, otherwise the toStdString() function above
wouldn't compile.

What puzzles me is that I've successfully compiled similar things
with std::strings, like this:

// Prints "Hello, world!":
const char* word1 = "Hello";
const char* word2 = "world";
printf("%s", (word1 + std::string(", ") + word2 + "!\n").c_str());

and have had no problems with it. (Basically, word1+std::string(", ")
+word2+"!\n" returns a std::string, and the ::c_str() method is called
on it, passing its internal data to printf() to use before the
std::string goes out of scope.)

I would think that what I'm trying to do with std::ostringstream is
really no different, so it puzzles me why (std::ostringstream() <<
num).str() generates a compiler error. Does anybody know why this
generates a compiler error?

Thanks in advance for any help.

-- Jean-Luc
Jun 27 '08 #1
9 3706
jl*****@hotmail.com wrote:
Hi,

A few months back I remember reading through C++ newsgroups trying
to find a way to quickly convert a number to a C++ std::string. I
often see code like:

// Create a string that holds a number:
int num = 7; // for example
char tmp[24];
sprintf(tmp, "%d", num);
const std::string str = tmp;

but I wanted to see if there was a better way. I generally would use
this:

// Create a string that holds a number:
int num = 7;
std::ostringstream outStream; // #include <sstream>
outStream << num;
const std::string str = outStream.str();

and this works great, but just like the first example, it declares and
uses a temporary variable/object. What I'd have liked to see was some
sort of method in std::string that handled the conversion in one line,
like this:

// NOTE: not real code!
int num = 7;
const std::string str = std::string::number(num);

While I didn't find what I was looking for, I did find an
interesting post, where someone posted this nice, simple function:

// Converts many things to a std::string:
#include <sstream>

template <typename T>
std::string toStdString(const T &thing)
{
std::ostringstream os;
os << thing;
return os.str();
}

Using this function, I can now write code like this:

int num = 7;
const std::string str = toStdString(num);

This code is very clear, but it also has another benefit: Not only
can I easily convert integers and floats to a std::string, but I can
convert pretty much anything that I can send to std::cout.

But then I thought of something: Why even define a templated
function? I could write code like this:

int num = 7;
std::string str = (std::ostringstream() << num).str();

It may not be as elegant as the toStdString() solution, but at least
it won't require me to define (or include a header file of) the
toStdString() function in every program I write. In addition, there's
no need to introduce a temporary variable to the current scope.

However, when I tried to compile this code, I got the following
error message:

testfile.cpp: In function `int main(int, char**)':
testfile.cpp:23: error: 'struct std::basic_ostream<char,
std::char_traits<char' has no member named 'str'
Note that the operator<< you are invoking is inherited from the
std::basic_ostream<char>. Its return type is std::basic_ostream&. At that
point, all information about the underlying object being a string stream is
lost. An std::basic_ostream<charobject does not have a str() member
function. You need to cast back:

std::string str =
static_cast< std::ostringstream& >( std::ostringstream() << num ).str();
[snip]
BTW: you should just put toStdString into your library and use it. It is
much better than writing a cryptic line every time you want to convert
something. Also, you are creating a stringstream object in either case.
Whether it is a named local variable of a temporary doesn't really matter
all that much.
Best

Kai-Uwe Bux
Jun 27 '08 #2
jl*****@hotmail.com kirjutas:
>
int num = 7;
std::string str = (std::ostringstream() << num).str();
ostringstream is derived from basic_ostream. The operator << you are
calling is the one from the basic_ostream class. It returns a reference to
itself as a reference to the basic_ostream class object. This class does
not have a str() member function.

As the object itself is actually ostringstream, you should be able to cast
it back to the correct type:

int num = 7;
std::string str = static_cast<std::ostringstream&>(std::ostringstrea m() <<
num).str();

Of course, this makes the one-liner even uglier. What's wrong with the
helper function approach?

hth
Paavo
Jun 27 '08 #3
Kai-Uwe Bux wrote:
jl*****@hotmail.com wrote:
>Hi,
[snip]
> int num = 7;
std::string str = (std::ostringstream() << num).str();

It may not be as elegant as the toStdString() solution, but at least
it won't require me to define (or include a header file of) the
toStdString() function in every program I write. In addition, there's
no need to introduce a temporary variable to the current scope.

However, when I tried to compile this code, I got the following
error message:

testfile.cpp: In function `int main(int, char**)':
testfile.cpp:23: error: 'struct std::basic_ostream<char,
std::char_traits<char' has no member named 'str'

Note that the operator<< you are invoking is inherited from the
std::basic_ostream<char>. Its return type is std::basic_ostream&. At that
point, all information about the underlying object being a string stream
is lost. An std::basic_ostream<charobject does not have a str() member
function. You need to cast back:

std::string str =
static_cast< std::ostringstream& >( std::ostringstream() << num ).str();
[snip]

Ah, and just for kicks, now try:

#include <sstream>
#include <iostream>

int main ( void ) {
char const * message = "Hello world.\n";
std::cout <<
static_cast< std::ostringstream& >
( std::ostringstream() << message ).str();
}

and interpret the output.
I re-iterate: go with the toStdString() solution.
Best

Kai-Uwe Bux
Jun 27 '08 #4
On Jun 17, 3:28*pm, Kai-Uwe Bux <jkherci...@gmx.netwrote:
Kai-Uwe Bux wrote:
jl_p...@hotmail.com wrote:
Hi,

[snip]
* *int num = 7;
* *std::string str = (std::ostringstream() << num).str();
It may not be as elegant as the toStdString() solution, but at least
it won't require me to define (or include a header file of) the
toStdString() function in every program I write. *In addition, there's
no need to introduce a temporary variable to the current scope.
* *However, when I tried to compile this code, I got the following
error message:
testfile.cpp: In function `int main(int, char**)':
testfile.cpp:23: error: 'struct std::basic_ostream<char,
std::char_traits<char' has no member named 'str'
Note that the operator<< you are invoking is inherited from the
std::basic_ostream<char>. Its return type is std::basic_ostream&. At that
point, all information about the underlying object being a string stream
is lost. An std::basic_ostream<charobject does not have a str() member
function. You need to cast back:
* std::string str =
* static_cast< std::ostringstream& >( std::ostringstream() << num ).str();

[snip]

Ah, and just for kicks, now try:

#include <sstream>
#include <iostream>

int main ( void ) {
* char const * message = "Hello world.\n";
* std::cout <<
* * static_cast< std::ostringstream& >
* * ( std::ostringstream() << message ).str();

}

and interpret the output.

I re-iterate: go with the toStdString() solution.

Best

Kai-Uwe Bux

Or get a hold of the boost libraries (boost.org) and use its
lexical_cast<>(). It not only converts from string to number and
number to string. But from anything to anything. As long as you can
use a stream to convert them. Even better boost is the semi-offical
testing ground for stuff that will be considered for the next
standard. So it is highly tested and widely addopted.

#include <boost/lexical_cast.hpp>

int main()
{
std::string val("567");
int num = boost::lexical_cast<int>(val);
}
Jun 27 '08 #5
On Jun 18, 1:03 am, Martin York <Martin.YorkAma...@gmail.comwrote:
On Jun 17, 3:28 pm, Kai-Uwe Bux <jkherci...@gmx.netwrote:
Kai-Uwe Bux wrote:
jl_p...@hotmail.com wrote:
[snip]
Or get a hold of the boost libraries (boost.org) and use its
lexical_cast<>(). It not only converts from string to number
and number to string. But from anything to anything.
I'm not sure that I'd consider that an advantage. It doesn't
make sense to convert anything to anything (and going through
the textual representation, which boost::lexical_cast does, is
not necessarily the correct way to convert x to y).

Even in the case of conversion to string, I'm not sure just how
often a generic solution is appropriate; you probably don't want
to format a value representing an interest rate (percent) in the
same way you'd format a value representing a monetary value.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 27 '08 #6
On Jun 18, 1:34*am, James Kanze <james.ka...@gmail.comwrote:
On Jun 18, 1:03 am, Martin York <Martin.YorkAma...@gmail.comwrote:
Or get a hold of the boost libraries (boost.org) and use its
lexical_cast<>(). It not only converts from string to number
and number to string. But from anything to anything.

I'm not sure that I'd consider that an advantage. *It doesn't
make sense to convert anything to anything (and going through
the textual representation, which boost::lexical_cast does, is
not necessarily the correct way to convert x to y).
Context is everything.
I hope (and imagine) other readers did not read into my last reply
that I was suggesting that lexical_cast<>() should be used to convert
from a type to any other arbitory type. Where appropriate stream can
be used (via lexical_cast<>()) in a type safe way to convert types
appropriately (Its usage will ALWAYS depend on the context of the
problem). 'Normally' this will be <Type=String or String =>
<Type>. But as with all rules and complex systems it usage is not
limited to just that.

Martin
Jun 27 '08 #7

Thank you all for all your help. I really appreciate it.

But before I end this post, let me answer a question some have been
asking:

On Jun 17, 3:21 pm, Paavo Helde <nob...@ebi.eewrote:
>
What's wrong with the helper function approach?
Nothing, really. I just wanted to know why the line:

std::string str = (std::ostringstream() << num).str();

wouldn't compile. That line to me is fairly simple (even thought some
might call it "ugly"), that if I were to find a just-as-simple
approach, I'd use that.

However, I agree that the fix that uses the static_cast:

std::string str =
static_cast<std::ostringstream&>
(std::ostringstream() << num).str();

is not that "pretty" and that there are more readable ways to do the
same thing.

(Basically, I wanted to know why the code wouldn't compile. I
didn't mean to imply that I rejected the helper-function approach.
Sorry for the confusion.)

Again, thanks for all your help.

-- Jean-Luc
Jun 27 '08 #8
On Jun 18, 8:22 pm, Martin York <Martin.YorkAma...@gmail.comwrote:
On Jun 18, 1:34 am, James Kanze <james.ka...@gmail.comwrote:
On Jun 18, 1:03 am, Martin York <Martin.YorkAma...@gmail.comwrote:
Or get a hold of the boost libraries (boost.org) and use
its lexical_cast<>(). It not only converts from string to
number and number to string. But from anything to
anything.
I'm not sure that I'd consider that an advantage. It
doesn't make sense to convert anything to anything (and
going through the textual representation, which
boost::lexical_cast does, is not necessarily the correct way
to convert x to y).
Context is everything.
I hope (and imagine) other readers did not read into my last
reply that I was suggesting that lexical_cast<>() should be
used to convert from a type to any other arbitory type. Where
appropriate stream can be used (via lexical_cast<>()) in a
type safe way to convert types appropriately (Its usage will
ALWAYS depend on the context of the problem). 'Normally' this
will be <Type=String or String =<Type>. But as with all
rules and complex systems it usage is not limited to just
that.
Yes. The problem with lexical_cast is that it is too
convenient; it sort of works in a large number of cases where it
probably shouldn't (and then fails for some particular values
which you forgot to test).

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 27 '08 #9
On Jun 18, 9:50*pm, jl_p...@hotmail.com wrote:
* *std::string str = (std::ostringstream() << num).str();

wouldn't compile. *That line to me is fairly simple (even thought some
might call it "ugly"), that if I were to find a just-as-simple
approach, I'd use that.
Using a utility class, a string builder, you can achieve this terse
solution:

string s = SB << num;

See here for discussion, description and limitations:

http://groups.google.com/group/comp....00421feca71ea1

Regards,
Vidar Hasfjord
Jun 27 '08 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
3727
by: Kostatus | last post by:
I have a virtual function in a base class, which is then overwritten by a function of the same name in a publically derived class. When I call the function using a pointer to the derived class...
4
2382
by: Leslaw Bieniasz | last post by:
Cracow, 20.09.2004 Hello, I need to implement a library containing a hierarchy of classes together with some binary operations on objects. To fix attention, let me assume that it is a...
15
2303
by: Tamblyne | last post by:
This problem has got to have a simple solution and I can't be the first person who has ever handled it. Perhaps Google is no help because I'm not using the right terms? (I did find one post...
15
2404
by: Ken Allen | last post by:
I have been developing a suite of assemblies over the past couple of weeks, and this afternoon somethign started misbehaving. If I do not run the IDE and compiler the code from the command line,...
4
2331
by: Sa¹o Zagoranski | last post by:
Hi! I'm writing a simple 3D First person shooter game. It is a multiplayer game, where all the players connect to one server.
8
3363
by: nick | last post by:
I have a problem and I've been using a cheezy work around and was wondering if anyone else out there has a better solution. The problem: Let's say I have a web application appA. Locally, I set...
9
9663
by: Ecohouse | last post by:
I have a main form with two subforms. The first subform has the child link to the main form identity key. subform1 - Master Field: SK Child Field: TrainingMasterSK The second subform has a...
9
5738
by: HC | last post by:
Hello, all, I started out thinking my problems were elsewhere but as I have worked through this I have isolated my problem, currently, as a difference between MSDE and SQL Express 2005 (I'll just...
1
2633
by: Kijoki | last post by:
Hi, I am having this big headache causing problem for over seven months now! I run an internetcafe and for over the past seven months I have been getting this really weird problem in which my...
9
3616
by: AceKnocks | last post by:
I am working on a framework design problem in which I have to design a C++ based framework capable of solving three puzzles for now but actually it should work with a general puzzle of any kind and I...
0
7049
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
6912
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
7092
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
6744
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
5348
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
4488
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
3000
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
2989
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
1304
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.