Is this the correct way to do this template?

Discussion in 'C++' started by Jim Langston, Jun 3, 2006.

  1. Jim Langston

    Jim Langston Guest

    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;
    }
     
    Jim Langston, Jun 3, 2006
    #1
    1. Advertising

  2. Jim Langston

    Kai-Uwe Bux Guest

    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;
    > }
    >
    > 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.

    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.

    > 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
     
    Kai-Uwe Bux, Jun 3, 2006
    #2
    1. Advertising

  3. Jim Langston

    Jim Langston Guest

    "Kai-Uwe Bux" <> wrote in message
    news:...
    > 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;
    >> }
    >>
    >> 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.


    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.

    >> 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;


    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.

    >> std::cout << StrmConvert( 123.45 ) << std::endl;
    >>
    >> float MyValue = StrmConvert<float>( "123.456" );
    >> std::cout << MyValue << std::endl;
    >>
    >> std::string wait;
    >> std::cin >> wait;
    >> }


    Thanks for the code revue.
     
    Jim Langston, Jun 3, 2006
    #3
  4. Jim Langston

    Kai-Uwe Bux Guest

    Jim Langston wrote:

    > "Kai-Uwe Bux" <> wrote in message
    > news:...
    >> 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.

    >
    >> 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.


    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
     
    Kai-Uwe Bux, Jun 3, 2006
    #4
  5. Jim Langston

    Jim Langston Guest

    "Kai-Uwe Bux" <> wrote in message
    news:...
    > Jim Langston wrote:
    >
    >> "Kai-Uwe Bux" <> wrote in message
    >> news:...
    >>> 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.
    >
    >>
    >>> 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.

    >
    > 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.
     
    Jim Langston, Jun 3, 2006
    #5
  6. Jim Langston

    Kai-Uwe Bux Guest

    Jim Langston wrote:

    >
    > "Kai-Uwe Bux" <> wrote in message
    > news:...
    >> Jim Langston wrote:
    >>
    >>> "Kai-Uwe Bux" <> wrote in message
    >>> news:...
    >>>> 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.



    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Jun 3, 2006
    #6
  7. Jim Langston

    Jim Langston Guest

    "Kai-Uwe Bux" <> wrote in message
    news:...
    > Jim Langston wrote:
    >
    >>
    >> "Kai-Uwe Bux" <> wrote in message
    >> news:...
    >>> Jim Langston wrote:
    >>>
    >>>> "Kai-Uwe Bux" <> wrote in message
    >>>> news:...
    >>>>> 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;
    }
     
    Jim Langston, Jun 3, 2006
    #7
  8. Jim Langston

    Kai-Uwe Bux Guest

    Jim Langston wrote:

    >
    > "Kai-Uwe Bux" <> wrote in message
    > news:...
    >> Jim Langston wrote:
    >>
    >>>
    >>> "Kai-Uwe Bux" <> wrote in message
    >>> news:...
    >>>> Jim Langston wrote:
    >>>>
    >>>>> "Kai-Uwe Bux" <> wrote in message
    >>>>> news:...
    >>>>>> 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
     
    Kai-Uwe Bux, Jun 3, 2006
    #8
  9. Jim Langston

    Jim Langston Guest

    "Kai-Uwe Bux" <> wrote in message
    news:...
    > Jim Langston wrote:
    >
    >>
    >> "Kai-Uwe Bux" <> wrote in message
    >> news:...
    >>> Jim Langston wrote:
    >>>
    >>>>
    >>>> "Kai-Uwe Bux" <> wrote in message
    >>>> news:...
    >>>>> Jim Langston wrote:
    >>>>>
    >>>>>> "Kai-Uwe Bux" <> wrote in message
    >>>>>> news:...
    >>>>>>> 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 );
    }
     
    Jim Langston, Jun 3, 2006
    #9
  10. Jim Langston

    Marcus Kwok Guest

    Kai-Uwe Bux <> wrote:
    > 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.

    --
    Marcus Kwok
    Replace 'invalid' with 'net' to reply
     
    Marcus Kwok, Jun 5, 2006
    #10
  11. Jim Langston

    Kai-Uwe Bux Guest

    Marcus Kwok wrote:

    > Kai-Uwe Bux <> wrote:
    >> 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.


    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
     
    Kai-Uwe Bux, Jun 5, 2006
    #11
  12. Jim Langston

    Jerry Coffin Guest

    In article <SCkgg.629$>,
    says...

    [ ... ]

    > 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);

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
     
    Jerry Coffin, Jun 7, 2006
    #12
  13. Jim Langston wrote:
    > 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. :-(
     
    Diego Martins, Jun 7, 2006
    #13
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. joon
    Replies:
    1
    Views:
    516
    Roedy Green
    Jul 8, 2003
  2. Dan

    correct or not correct?

    Dan, Oct 2, 2003, in forum: HTML
    Replies:
    7
    Views:
    445
  3. J.Ram
    Replies:
    7
    Views:
    654
  4. m0shbear
    Replies:
    2
    Views:
    349
  5. froil
    Replies:
    12
    Views:
    315
    Gunnar Hjalmarsson
    Mar 2, 2006
Loading...

Share This Page