Is this the correct way to do this template?

J

Jim Langston

I have a template I call StrmConvert, which uses std::stringstream to
convert from any type to any other type that can be used by stringstring.
This is what it looks like:

template<typename T, typename F > T StrmConvert( F from )
{
std::stringstream temp;
temp << from;
T to = T();
temp >> to;
return to;
}

it works well for me, but I find it can be a lot of typing. I have it in a
namespace called jml so I wind up doing things like this:

std::cout << jml::StrmConvert<std::string>( floatvalue );

I find that 99% of the time I'm converting to std::string so I've decided to
specialize it (if that is the right term) this way:

template<typename F> std::string StrmConvert( F from )
{
return StrmConvert<std::string>( from );
}

and it seems to work. Now I can say:

std::cout << jml::StrmConvert( floatvalue );

because if I don't specify the typename T is uses the std::string. Is this
the right way to do it? It seems to work, but I want to know if there can
be any problems with this. I did this test and it works, I'm just a n00b
when it comes to templates.

#include <string>
#include <iostream>
#include <sstream>

template<typename T, typename F > T StrmConvert( F from )
{
std::stringstream temp;
temp << from;
T to = T();
temp >> to;
return to;
}

template<typename F> std::string StrmConvert( F from )
{
return StrmConvert<std::string>( from );
}

int main ()
{

std::cout << StrmConvert<std::string>( 123.45 ) << std::endl;
std::cout << StrmConvert( 123.45 ) << std::endl;

float MyValue = StrmConvert<float>( "123.456" );
std::cout << MyValue << std::endl;

std::string wait;
std::cin >> wait;
}
 
K

Kai-Uwe Bux

Jim said:
I have a template I call StrmConvert, which uses std::stringstream to
convert from any type to any other type that can be used by stringstring.
This is what it looks like:

template<typename T, typename F > T StrmConvert( F from )
{
std::stringstream temp;
temp << from;
T to = T();
temp >> to;
return to;
}

it works well for me, but I find it can be a lot of typing. I have it in
a namespace called jml so I wind up doing things like this:

std::cout << jml::StrmConvert<std::string>( floatvalue );

I find that 99% of the time I'm converting to std::string so I've decided
to specialize it (if that is the right term) this way:

template<typename F> std::string StrmConvert( F from )
{
return StrmConvert<std::string>( from );
}

and it seems to work. Now I can say:

std::cout << jml::StrmConvert( floatvalue );

because if I don't specify the typename T is uses the std::string. Is
this
the right way to do it? It seems to work, but I want to know if there can
be any problems with this. I did this test and it works, I'm just a n00b
when it comes to templates.

#include <string>
#include <iostream>
#include <sstream>

template<typename T, typename F > T StrmConvert( F from )
{
std::stringstream temp;
temp << from;
T to = T();

T to;
temp >> to;
return to;
}

Also, you may want to throw something if the conversion fails. Anyhow,
boost::lexical_cast is maybe what you try to reinvent here.
template<typename F> std::string StrmConvert( F from )
{
return StrmConvert<std::string>( from );
}

int main ()
{

std::cout << StrmConvert<std::string>( 123.45 ) << std::endl;

I fail to see what that buys you compared to

std::cout << 123.45 << std::endl;

Also note that the StrmConvert<> is broken with regard to float types:
conversion will not even remotely make a round-trip:

double x;
double y = StrmConvert<double>( x );

This will turn y into a 6-digit precission approximation (I think << has a
default precision like that). Usually that is not what you want.

std::cout << StrmConvert( 123.45 ) << std::endl;

float MyValue = StrmConvert<float>( "123.456" );
std::cout << MyValue << std::endl;

std::string wait;
std::cin >> wait;
}


Best

Kai-Uwe Bux
 
J

Jim Langston

Kai-Uwe Bux said:
T to;


Also, you may want to throw something if the conversion fails.

I've thought about throwing, but then I would need to catch every time I use
StrmConvert, which is a lot. I would rather take the default value which is
what the T(); should be giving me. If there is a case where I want to know
if it's a bad value, I'll test for it outside the template before I call it
or after.
Anyhow,
boost::lexical_cast is maybe what you try to reinvent here.

Most likely. I just don't use, but once it becomes part of the standard I
will.
I fail to see what that buys you compared to

std::cout << 123.45 << std::endl;

Well, usually this would be used for outputing text using a graphical call.
Something like:
draw_text( x, y, "The value is: " + jml::StrmConvert( HPs ) );

The std::cout here was just done for my test since it gained me nothing to
bring in all my graphical code for a test.
Also note that the StrmConvert<> is broken with regard to float types:
conversion will not even remotely make a round-trip:

double x;
double y = StrmConvert<double>( x );

This will turn y into a 6-digit precission approximation (I think << has a
default precision like that). Usually that is not what you want.

Luckily for me, this is usually what I want. As I said, this is normally
used for simple output. Incidently, if I do need precision, is there anyway
I can fix it?
Also note that operator<< and operator>> are not strict inverses for some
other types (e.g., std::string). Your cast may lead to surprising results.

Please explain? I don't understand what you're saying here.

Thanks for the code revue.
 
K

Kai-Uwe Bux

Jim said:
Kai-Uwe Bux said:
Jim said:
I have a template I call StrmConvert, which uses std::stringstream to
convert from any type to any other type that can be used by
stringstring. This is what it looks like:

template<typename T, typename F > T StrmConvert( F from )
{
std::stringstream temp;
temp << from;
T to = T();
temp >> to;
return to;
} [snip]
int main ()
{

std::cout << StrmConvert<std::string>( 123.45 ) << std::endl;

I fail to see what that buys you compared to

std::cout << 123.45 << std::endl;

Well, usually this would be used for outputing text using a graphical
call. Something like:
draw_text( x, y, "The value is: " + jml::StrmConvert( HPs ) );

The std::cout here was just done for my test since it gained me nothing to
bring in all my graphical code for a test.
Also note that the StrmConvert<> is broken with regard to float types:
conversion will not even remotely make a round-trip:

double x;
double y = StrmConvert<double>( x );

This will turn y into a 6-digit precission approximation (I think << has
a default precision like that). Usually that is not what you want.

Luckily for me, this is usually what I want. As I said, this is normally
used for simple output. Incidently, if I do need precision, is there
anyway I can fix it?

Yes, you would need to set the precision of the stringstream to the right
value. You could either have the template do that based upon the floating
type (partial specialization) or you pass a precision parameter as a second
argument and have it default to something reasonable.
Please explain? I don't understand what you're saying here.

Well, I mistook your template for a cast. So I was concerned with code like:

std::string s = "hello world!";
std::string t = my_fancy_cast< std::string >( s );

Now, given the naive stringstream implementation, the string t will
be "hello" and not "hello world!".



Now that I know you just want to convert to std::string so that you can
output anything via some API that takes strings or C-Strings, what about:

template< typename T >
std::string any_to_string ( T const & obj ) {
std::stringstream dummy;
if ( !( dummy << obj ) ) {
throw( std::runtime_error( "conversion to string failed" ) );
}
return dummy.str();
}

or:

template< typename T >
std::string any_to_string ( T const & obj, unsigned short prec = 6 ) {
std::stringstream dummy;
if ( !( dummy << std::setprecision(prec) << obj ) ) {
throw( std::runtime_error( "conversion to string failed" ) );
}
return dummy.str();
}


Best

Kai-Uwe Bux
 
J

Jim Langston

Kai-Uwe Bux said:
Jim said:
Kai-Uwe Bux said:
Jim Langston wrote:

I have a template I call StrmConvert, which uses std::stringstream to
convert from any type to any other type that can be used by
stringstring. This is what it looks like:

template<typename T, typename F > T StrmConvert( F from )
{
std::stringstream temp;
temp << from;
T to = T();
temp >> to;
return to;
} [snip]
int main ()
{

std::cout << StrmConvert<std::string>( 123.45 ) << std::endl;

I fail to see what that buys you compared to

std::cout << 123.45 << std::endl;

Well, usually this would be used for outputing text using a graphical
call. Something like:
draw_text( x, y, "The value is: " + jml::StrmConvert( HPs ) );

The std::cout here was just done for my test since it gained me nothing
to
bring in all my graphical code for a test.
Also note that the StrmConvert<> is broken with regard to float types:
conversion will not even remotely make a round-trip:

double x;
double y = StrmConvert<double>( x );

This will turn y into a 6-digit precission approximation (I think << has
a default precision like that). Usually that is not what you want.

Luckily for me, this is usually what I want. As I said, this is normally
used for simple output. Incidently, if I do need precision, is there
anyway I can fix it?

Yes, you would need to set the precision of the stringstream to the right
value. You could either have the template do that based upon the floating
type (partial specialization) or you pass a precision parameter as a
second
argument and have it default to something reasonable.
Please explain? I don't understand what you're saying here.

Well, I mistook your template for a cast. So I was concerned with code
like:

std::string s = "hello world!";
std::string t = my_fancy_cast< std::string >( s );

Now, given the naive stringstream implementation, the string t will
be "hello" and not "hello world!".



Now that I know you just want to convert to std::string so that you can
output anything via some API that takes strings or C-Strings, what about:

template< typename T >
std::string any_to_string ( T const & obj ) {
std::stringstream dummy;
if ( !( dummy << obj ) ) {
throw( std::runtime_error( "conversion to string failed" ) );
}
return dummy.str();
}

or:

template< typename T >
std::string any_to_string ( T const & obj, unsigned short prec = 6 ) {
std::stringstream dummy;
if ( !( dummy << std::setprecision(prec) << obj ) ) {
throw( std::runtime_error( "conversion to string failed" ) );
}
return dummy.str();
}

Well, sometimes I do use it to convert from strings to numbers, usually int
values.

The main use I'm using this for right now is a client/server program (game)
building and parsing strings from and to the server. Here is one real world
case of where I'm using it for this:

// Note, this is char value like "64", not a byte

CSVParser & CSVParser::eek:perator >> (char & nOut)
{
GetField();
int tInt = jml::StrmConvert<int>( m_sField );
nOut = (char) tInt;
return *this;
}

CSVParser & CSVParser::eek:perator >> (unsigned int & nOut)
{
GetField();
nOut = jml::StrmConvert<unsigned int>( m_sField );
return *this;
}

CSVParser & CSVParser::eek:perator >> (unsigned long & nOut)
{
GetField();
nOut = jml::StrmConvert<unsigned long>( m_sField );
return *this;
}

CSVParser & CSVParser::eek:perator >> (double & nOut)
{
GetField();
nOut = jml::StrmConvert<double>( m_sField );
return *this;
}

The use for double does concern me, given your comment about the precision
problems, which is why I asked how to fix it. There are some cases where
I'm transfering a float value with a number of decimal digits I need to
preserve. So far it hasn't caused any problems, but later on it will so I
will need to fix it.

Giving an optional 3rd paramter for places of precision would probably be my
best bet.
 
K

Kai-Uwe Bux

Jim said:
[snip]

The use for double does concern me, given your comment about the precision
problems, which is why I asked how to fix it. There are some cases where
I'm transfering a float value with a number of decimal digits I need to
preserve. So far it hasn't caused any problems, but later on it will so I
will need to fix it.

Giving an optional 3rd paramter for places of precision would probably be
my best bet.

Ok, here is a hack that I use to determine how many digits I need to print
in order to preserve the accuracy.


#include <iostream>
#include <limits>
#include <cmath>

template < typename T >
unsigned short max_prec ( void ) {
return
2 +
static_cast< unsigned short >
( - std::log( std::numeric_limits<T>::epsilon() ) / std::log( 10.0 ) );
}

int main ( void ) {
std::cout << "float: " << max_prec< float >() << '\n'
<< "double: " << max_prec< double >() << '\n'
<< "long double: " << max_prec< long double >() << '\n';
}


If you use max_prec() digits, you should be fine -- if it wasn't for the
usual pitfalls of floats, that is.



Best

Kai-Uwe Bux
 
J

Jim Langston

Kai-Uwe Bux said:
Jim said:
Kai-Uwe Bux said:
Jim Langston wrote:

Jim Langston wrote:

I have a template I call StrmConvert, which uses std::stringstream to
convert from any type to any other type that can be used by
stringstring. This is what it looks like:

template<typename T, typename F > T StrmConvert( F from )
{
std::stringstream temp;
temp << from;
T to = T();
temp >> to;
return to;
}
[snip]

The use for double does concern me, given your comment about the
precision
problems, which is why I asked how to fix it. There are some cases where
I'm transfering a float value with a number of decimal digits I need to
preserve. So far it hasn't caused any problems, but later on it will so
I
will need to fix it.

Giving an optional 3rd paramter for places of precision would probably be
my best bet.

Ok, here is a hack that I use to determine how many digits I need to print
in order to preserve the accuracy.


#include <iostream>
#include <limits>
#include <cmath>

template < typename T >
unsigned short max_prec ( void ) {
return
2 +
static_cast< unsigned short >
( - std::log( std::numeric_limits<T>::epsilon() ) / std::log( 10.0 ) );
}

int main ( void ) {
std::cout << "float: " << max_prec< float >() << '\n'
<< "double: " << max_prec< double >() << '\n'
<< "long double: " << max_prec< long double >() << '\n';
}


If you use max_prec() digits, you should be fine -- if it wasn't for the
usual pitfalls of floats, that is.

Bah, std::stringstream ignores precision on text input. That is, the follow
program outputs:
1.2345678901229999
1.23457

I guess std::stringstream can't convert from a text string to a floating
point value with any type of accuracy.

#include <iostream>
#include <string>
#include <sstream>

int main ( void )
{
std::stringstream MyStream;
MyStream.precision( 18 );

double DoubleVal = 1.234567890123;
std::string Text;

MyStream << DoubleVal;
MyStream >> Text;
std::cout << Text << std::endl;

MyStream << Text;
MyStream >> DoubleVal;
std::cout << DoubleVal << std::endl;

std::string wait;
std::cin >> wait;
}
 
K

Kai-Uwe Bux

Jim said:
Kai-Uwe Bux said:
Jim said:
Jim Langston wrote:

Jim Langston wrote:

I have a template I call StrmConvert, which uses std::stringstream
to convert from any type to any other type that can be used by
stringstring. This is what it looks like:

template<typename T, typename F > T StrmConvert( F from )
{
std::stringstream temp;
temp << from;
T to = T();
temp >> to;
return to;
} [snip]

The use for double does concern me, given your comment about the
precision
problems, which is why I asked how to fix it. There are some cases
where I'm transfering a float value with a number of decimal digits I
need to
preserve. So far it hasn't caused any problems, but later on it will so
I
will need to fix it.

Giving an optional 3rd paramter for places of precision would probably
be my best bet.

Ok, here is a hack that I use to determine how many digits I need to
print in order to preserve the accuracy.


#include <iostream>
#include <limits>
#include <cmath>

template < typename T >
unsigned short max_prec ( void ) {
return
2 +
static_cast< unsigned short >
( - std::log( std::numeric_limits<T>::epsilon() ) / std::log( 10.0 )
);
}

int main ( void ) {
std::cout << "float: " << max_prec< float >() << '\n'
<< "double: " << max_prec< double >() << '\n'
<< "long double: " << max_prec< long double >() << '\n';
}


If you use max_prec() digits, you should be fine -- if it wasn't for the
usual pitfalls of floats, that is.

Bah, std::stringstream ignores precision on text input.
Huh?

That is, the
follow program outputs:
1.2345678901229999
1.23457

Ok, let's see.
I guess std::stringstream can't convert from a text string to a floating
point value with any type of accuracy.

It is supposed to.
#include <iostream>
#include <string>
#include <sstream>

int main ( void )
{
std::stringstream MyStream;
MyStream.precision( 18 );

double DoubleVal = 1.234567890123;
std::string Text;

MyStream << DoubleVal;
MyStream >> Text;
std::cout << Text << std::endl;

MyStream << Text;
MyStream >> DoubleVal;
std::cout << DoubleVal << std::endl;

Aha! Here, you print DoubleVal to std::cout with 6 digits of precision!
std::string wait;
std::cin >> wait;
}


Best

Kai-Uwe Bux
 
J

Jim Langston

Kai-Uwe Bux said:
Jim said:
Kai-Uwe Bux said:
Jim Langston wrote:


Jim Langston wrote:

Jim Langston wrote:

I have a template I call StrmConvert, which uses std::stringstream
to convert from any type to any other type that can be used by
stringstring. This is what it looks like:

template<typename T, typename F > T StrmConvert( F from )
{
std::stringstream temp;
temp << from;
T to = T();
temp >> to;
return to;
}
[snip]

The use for double does concern me, given your comment about the
precision
problems, which is why I asked how to fix it. There are some cases
where I'm transfering a float value with a number of decimal digits I
need to
preserve. So far it hasn't caused any problems, but later on it will
so
I
will need to fix it.

Giving an optional 3rd paramter for places of precision would probably
be my best bet.

Ok, here is a hack that I use to determine how many digits I need to
print in order to preserve the accuracy.


#include <iostream>
#include <limits>
#include <cmath>

template < typename T >
unsigned short max_prec ( void ) {
return
2 +
static_cast< unsigned short >
( - std::log( std::numeric_limits<T>::epsilon() ) / std::log( 10.0 )
);
}

int main ( void ) {
std::cout << "float: " << max_prec< float >() << '\n'
<< "double: " << max_prec< double >() << '\n'
<< "long double: " << max_prec< long double >() << '\n';
}


If you use max_prec() digits, you should be fine -- if it wasn't for the
usual pitfalls of floats, that is.

Bah, std::stringstream ignores precision on text input.
Huh?

That is, the
follow program outputs:
1.2345678901229999
1.23457

Ok, let's see.
I guess std::stringstream can't convert from a text string to a floating
point value with any type of accuracy.

It is supposed to.
#include <iostream>
#include <string>
#include <sstream>

int main ( void )
{
std::stringstream MyStream;
MyStream.precision( 18 );

double DoubleVal = 1.234567890123;
std::string Text;

MyStream << DoubleVal;
MyStream >> Text;
std::cout << Text << std::endl;

MyStream << Text;
MyStream >> DoubleVal;
std::cout << DoubleVal << std::endl;

Aha! Here, you print DoubleVal to std::cout with 6 digits of precision!
std::string wait;
std::cin >> wait;
}

Well, now I really feel like a n00b. lol.

Thanks. I've settled on always setting the precision to 17 since I was
having trouble calling your template if the F wasn't a float or double, and
even inside an if block if (typeid(F) == typeid(double) ).. it wouldn't
compile because even though it would never run that code it insisted on
compiling it anyway.

template<typename T, typename F > T StrmConvert( F from )
{
std::stringstream temp;
temp.precision( 17 );
temp << from;
T to = T();
temp >> to;
return to;
}

template<typename F> std::string StrmConvert( F from )
{
return StrmConvert<std::string>( from );
}
 
M

Marcus Kwok

Kai-Uwe Bux said:
Ok, here is a hack that I use to determine how many digits I need to print
in order to preserve the accuracy.


#include <iostream>
#include <limits>
#include <cmath>

template < typename T >
unsigned short max_prec ( void ) {
return
2 +
static_cast< unsigned short >
( - std::log( std::numeric_limits<T>::epsilon() ) / std::log( 10.0 ) );
}

int main ( void ) {
std::cout << "float: " << max_prec< float >() << '\n'
<< "double: " << max_prec< double >() << '\n'
<< "long double: " << max_prec< long double >() << '\n';
}

Is there any difference between using this and
(2 + std::numeric_limits::digits10)? Using the same definition for
max_prec() that you have,

int main ( void ) {
std::cout << "float: " << max_prec< float >() << '\n'
<< "double: " << max_prec< double >() << '\n'
<< "long double: " << max_prec< long double >() << '\n';

std::cout << "float: " << 2 + std::numeric_limits<float>::digits10 << '\n'
<< "double: " << 2 + std::numeric_limits<double>::digits10 << '\n'
<< "long double: " << 2 + std::numeric_limits<long double>::digits10 << '\n';
}

both sets display the same values. Also, I am not sure why we need to
add 2.
 
K

Kai-Uwe Bux

Marcus said:
Is there any difference between using this and
(2 + std::numeric_limits::digits10)? Using the same definition for
max_prec() that you have,

int main ( void ) {
std::cout << "float: " << max_prec< float >() << '\n'
<< "double: " << max_prec< double >() << '\n'
<< "long double: " << max_prec< long double >() << '\n';

std::cout << "float: " << 2 + std::numeric_limits<float>::digits10 <<
'\n'
<< "double: " << 2 + std::numeric_limits<double>::digits10 << '\n'
<< "long double: " << 2 + std::numeric_limits<long double>::digits10 <<
'\n'; }

both sets display the same values. Also, I am not sure why we need to
add 2.

I am not sure. The standard has a very brief description of
digits10: "number of 10 digits that can be represented without change". I
take that to mean that this is a lower bound for the precision: if you have
a decimal number of up to digits10 digits, you can represent it so that you
can get your leading digits back. However, max_prec() tries to solve a
slightly different problem: print as many digits as necessary to
reconstruct the original floating point number. That also explains the
+2 -- I just erred on the side of caution.


Best

Kai-Uwe Bux
 
J

Jerry Coffin

[ ... ]
Well, usually this would be used for outputing text using a graphical call.
Something like:
draw_text( x, y, "The value is: " + jml::StrmConvert( HPs ) );

I tend to do this in the reverse direction: create a
manipulator to draw the contents of a stringstream:

std::stringstream temp;

temp << "The value is: " << HPs << draw_text(x, y);
 
D

Diego Martins

Jim said:
The main use I'm using this for right now is a client/server program (game)
building and parsing strings from and to the server. Here is one real world
case of where I'm using it for this:

// Note, this is char value like "64", not a byte

CSVParser & CSVParser::eek:perator >> (char & nOut)
{
GetField();
int tInt = jml::StrmConvert<int>( m_sField );
nOut = (char) tInt;
return *this;
}

[megasnip]

Why do many people put a big C in front of any class? C is a strong
letter and it makes the source code more rounded.

I hate M$ code-styles. :-(
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top