• Advertisement
Sign in to follow this  

C++17's from_chars

Recommended Posts

I consider using the C++17's

std::from_chars_result from_chars(const char* first, const char* last, ...);

due to its nice error codes (including range checking, whereas strtof etc. need to call GetLastError :S ).

I typically have three variants for converting a C string:

  • convert the C string [first, implicit last)
  • convert the C string [first, last)
  • convert the C string [first, implicit last) prefix

So for example,  "10K" will be converted to an integer 10 in the last case.

Is it somehow possible to do this as well with from_chars?

 

 

 

 

Share this post


Link to post
Share on other sites
Advertisement
#include <iostream>
#include <charconv>
#include <array>
 
int main() {
    std::array<char, 10> str{"42K"};
    int result;
    std::from_chars_result r = std::from_chars(str.data(), str.data()+str.size(), result);
    if (r.ec != std::errc::invalid_argument) {
        std::cout << "DAMN";
    }
    std::cout << result;
}

How could I avoid the "DAMN", but still know that I parsed at least one character without converting the first character explicitly.

Using the strtof family of functions, we can just do something like:

TokenResult StringToF64(const char *str, F64 &result) noexcept {
        if (!str) {
            return TokenResult::None;
        }

        char *inner_context = nullptr;
        result = strtod(str, &inner_context);
        return ('\0' == *inner_context) ? 
            TokenResult::Valid : TokenResult::Invalid;
    }

TokenResult StringToF64(const char *begin, const char *end, F64 &result) noexcept {
        if (!begin) {
            return TokenResult::None;
        }

        Assert(end);

        char *inner_context = nullptr;
        result = strtod(begin, &inner_context);
        return (end == inner_context) ? TokenResult::Valid : TokenResult::Invalid;
    }

TokenResult StringPrefixToF64(const char *str, F64 &result) noexcept {
        if (!str) {
            return TokenResult::None;
        }

        char *inner_context = nullptr;
        result = strtod(str, &inner_context);
        return (str != inner_context) ? 
            TokenResult::Valid : TokenResult::Invalid;
    }

 

Edited by matt77hias

Share this post


Link to post
Share on other sites
On 12/2/2017 at 4:16 PM, matt77hias said:

if (r.ec != std::errc::invalid_argument) {         std::cout << "DAMN";     }

This should use == instead of !=. But the problem now remains for the other case.

How are you capable of differentiating between "10" and "10k"?

Share this post


Link to post
Share on other sites

Solved! You get a pointer as well (pretty similar to the inner context)

#include <iostream>
#include <charconv>
#include <array>
 
int main() {
    const char * const str1 = "10";
    const char * const str2 = "10K";
    int result1, result2;
    std::from_chars_result r1 = std::from_chars(str1, nullptr, result1);
    std::from_chars_result r2 = std::from_chars(str2, nullptr, result2);
    
    std::cout << result1 << std::endl;
    std::cout << result2 << std::endl;
    std::cout << static_cast< size_t >(r1.ec) << std::endl;
    std::cout << static_cast< size_t >(r2.ec) << std::endl;
    std::cout << (*r1.ptr) << std::endl;
    std::cout << (*r2.ptr) << std::endl;
}

 

As a side note what is the best design:

StringToS8, StringToS16, StringToS32, StringToS64

StringToU8, StringToU16, StringToU32, StringToU64

StringToF32, StringToF64

or overloading

FromString< T >?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Advertisement