Menu

#87 from_tstring — the to_tstring converse function

Owlet
pending
API (105)
1
2023-09-10
2014-12-19
Joe Slater
No

There are various flavors of converting a string to a number (e.g. _ttol, _ttof), but not all conversions are readily available and require different functions. I propose a single from_tstring function added in "defs.h" such as the following:

template <class T> T from_tstring (const tstring& s)
{ T n; tistringstream ts; ts.str(s); ts >> n; return n; }

This would allow any type of conversion from a tstring to a type that supports streaming (e.g. char, int, long, long long, unsigned versions of those). Example use:

tstring s = _T("+123456890123456");
auto n = from_tstring<unsigned long long>(s);
auto c = from_tstring<tchar>(s);

After the above executes, n = 123456890123456 and c = _T('+').

Discussion

  • Vidar Hasfjord

    Vidar Hasfjord - 2014-12-19
    • labels: API, Internal --> API
    • summary: Create converse function to to_tstring in defs.h --> Converse function to to_tstring


    I think from_tstring is a very good idea. It is symmetric with to_tstring and, like you point out, replaces the myriad of alternatives by a simple go-to solution for tstring, making it less likely that the user will write old-style code that is non-compliant with Unicode build mode.

    A few comments:

    • from_tstring needs error handling.
    • tistringstream's constructor taking tstring can be used.
    • Doxygen


    Suggested improvement:

    //
    /// Converts the given string to the given type T.
    /// Requires: DefaultConstructible<T> && Streamable<T>
    /// Succeeds if string stream extraction of T succeeds.
    /// Throws tistringstream::failure on failure.
    /// \note The whole string may not be used in the conversion. The
    /// function converts only as many characters as needed for string
    /// stream extraction of T.
    //
    template <class T>
    auto from_tstring(const tstring& s) -> T
    {
      auto is = tistringstream{s};
      is.exceptions(is.failbit);
      T v; is >> v;
      return v;
    }
    


    PS. I think to_tstring and from_tstring need a better home than "defs.h". I think we really should have "tstring.h", which in turn could include "private/strmdefs.h", where tistringstream etc. is defined. Or, we could simply remove the latter and include it literally in "tstring.h".

     

    Last edit: Vidar Hasfjord 2021-02-19
  • Vidar Hasfjord

    Vidar Hasfjord - 2014-12-19

    I have now implemented to_tstring and from_tstring in the new header "include/owl/tstring.h" on the Owlet branch [r2942].

     

    Related

    Commit: [r2942]

  • Joe Slater

    Joe Slater - 2014-12-20

    Hi Vidar,

    I think from_tstring is a very good idea
     

    Actually I think it and to_string is a not-so-good idea.

    I think to_tstring and from_tstring need a better home than "defs.h"
     

    As do I. But I think it further illustrates the need to extend tstring, which can't be done. I believe it in essence belongs in TStringC, with implicit conversions (constructors) and overload operators, simply allowing the following:

    TStringC s("12376571");
    long val1 = s;
    // …
    double val2 = 4.12387618273681;
    s = val;
    

    However, since you already added a to_tstring and TStringC has not been approved, I suggested the from_tstring.

     
  • Vidar Hasfjord

    Vidar Hasfjord - 2014-12-22
    • Group: unspecified --> 7
     
  • Joe Slater

    Joe Slater - 2015-01-19
    • assigned_to: Joe Slater --> nobody
     
  • Joe Slater

    Joe Slater - 2015-01-19

    Hi Vidar,

    In my usage of these new definitions, I have found them to be lacking for my purpose. Here are some definitions I use (in brevity, without error checking):

    template <class T> T from_tstring (const owl::tstring& s)
    { T n; owl::tistringstream ts; ts.str(s); ts >> n; return n; }
    
    template <class T> T from_tstring (const owl::tstring& s, const owl::tistringstream& ts)
    { T n; ts.str(s); ts >> n; return n; }
    
    template <class T> T from_tstring_locale (const owl::tstring& s, std::locale loc = std::locale(""))
    { owl::tistringstream ts; ts.imbue(loc); return (from_tstring(s, ts)); }
    
    template <class T> owl::tstring to_tstring(const T n, owl::tostringstream& ts)
    { ts << n; return ts.str(); }
    
    template <class T> owl::tstring to_tstring_locale(const T n, std::locale loc = std::locale(""))
    { owl::tostringstream ts; ts.imbue(loc); return (to_tstring(n, ts)); }
    

    The most commonly used for me is to_tstring_locale, which for example when called with:

    to_tstring_locale(-1234567890)
    

    gives me "-1,234,567,890" in the US locale. Other locales might give such results as "1.234.567.890-" or "(1 234 567 890)" as grouping and signed quantities yield different results. The inverse from_tstring_locale would also interpret such strings and return the proper result.

    However, there are other cases where even this is insufficient, such as using floating point numbers and wanting to specify control over the number of decimal places, or fill and width values, or monetary values. So I also have to_tstring/from_tstring with a stream argument so that the user can set these appropriately before calling them.

     
  • Vidar Hasfjord

    Vidar Hasfjord - 2015-01-24

    Hi Joe, sorry for the late reply. I am travelling (work/vacation) so I do not have much time for OWLNext at the moment. But I will return with more feedback as time allows.

    [to_tstring overloads and to_tstring_locale]

    Looks useful! And I cannot immediately see any ill-effects. Could we use simple overloading of "to_tstring" rather than add "to_tstring_locale"? Or are there overloading issues?

     
  • Joe Slater

    Joe Slater - 2015-02-04

    Hi Vidar,

    No need to apologize for being on vacation! Hope you are having a wonderful time.

    My reason for adding "to_tstring_locale" was to be able to use the default environment locale (i.e., locale("")) — which for me uses the US locale — without having to specify it while not breaking the existing behaviour of "to_tstring" (which in essence has a default locale("C")). I find both versions useful. The new addition is more user-friendly for displaying numeric values, but the existing one is needed for example, generating HTML entities for values greater than 999 (e.g., &#8229;) in which such group separators are undesired.

     
  • Vidar Hasfjord

    Vidar Hasfjord - 2015-02-05

    Makes sense.

     
  • Vidar Hasfjord

    Vidar Hasfjord - 2021-02-19

    I have made some corrections and improvements to from_tstring in Owlet [r5382].

    The new specialisations make from_tstring the proper converse to to_string for std::string and std::wstring. For example:

    OWL_CHECK("a test"s == from_tstring<string>(to_tstring("a test"s));
    OWL_CHECK(L"a test"s == from_tstring<wstring>(to_tstring(L"a test"s));
    

    Previously, using from_string with std::string and std::wstring as the template argument T caused compilation error, unless T matched owl::tstring. And if T matched owl::tstring, then only the first word of the string would be returned, not the whole string, i.e. causing our test above to fail.

    Note that these specialisations are implemented in terms of the new functions ConvertToNarrow and ConvertToWide [feature-requests:#174]. So an alternative to from_tstring is to use ConvertToNarrow and ConvertToWide instead, for perhaps clearer code. Though, in generic code, the from_tstring specialisations may still be useful, since the selection of the conversion operation depends on the template argument passed. However, the specialisations are mainly added for completeness and symmetry.

     

    Related

    Commit: [r5382]
    Feature Requests: #174


    Last edit: Vidar Hasfjord 2021-02-20
  • Vidar Hasfjord

    Vidar Hasfjord - 2021-02-19
    • assigned_to: Vidar Hasfjord
     
  • Vidar Hasfjord

    Vidar Hasfjord - 2021-02-21
    • assigned_to: Vidar Hasfjord --> nobody
    • Group: 7 --> unspecified
     
  • Vidar Hasfjord

    Vidar Hasfjord - 2023-09-10
    • assigned_to: Vidar Hasfjord
    • Group: unspecified --> Owlet
     
  • Vidar Hasfjord

    Vidar Hasfjord - 2023-09-10
    • status: open --> pending
     

Anonymous
Anonymous

Add attachments
Cancel