简体   繁体   中英

Convert std::string_view to float

I am trying to convert std::string_view to float without an intermediate conversion to std::string (which will cause extra heap allocation) with a C++20 compiler.

#include <iostream>
#include <charconv>

int main() {
    std::string_view s = "123.4";
    float x;
    std::from_chars(s.data(), s.data() + s.size(), x);
        
    std::cout << x << std::endl;
}

But I am unable to compile this code :

error: no matching function for call to 'from_chars(std::basic_string_view<char>::const_pointer, std::basic_string_view<char>::const_pointer, float&)'

What I am doing wrong?

GCC's C++ standard library implementation first supported std::from_chars for float in GCC 11.1 . 10.x won't support it.

Since you're not checking for success, and you know your string is null-terminated, you can use atof() instead, which is similarly unsafe. If you want proper checking for parsing errors, use strtof , which will give you similar information to from_chars as to whether the input matched properly:

#include <iostream>
#include <cstdlib>

int main() {
    std::string_view s = "123.4";
    char * end;
    float x = std::strtof(s.data(), &end);
    if (end != s.data() + s.size())
    {
        std::cout << "Parse error";
    }
    else
    {
        std::cout << x << std::endl;
    }
}

If and only if you know that your string view is null terminated, you can use this

float x = static_cast<float>(atof(s.data()));

Look into charconv header. For example GCC have next guard in it

#if defined __cpp_lib_to_chars || _GLIBCXX_HAVE_USELOCALE

So it can be not implemented, or your compiler not configured to use at least C++ 17 standard. Ie no -std=c++20 for GCC and Clang or /std:c++latest for Microsoft VC++ command line options passed to your compiler, or your implementation ie port not implementing this functionality and not fully implement a standard.

You always can replace from_chars with strtof c function.

For example:

#include <iostream>
#include <string_view>
#include <system_error>
#include <cmath>
#include <charconv>
#include <cstdlib>

int main(int argc, const char** argv)
{
    std::string_view sv("12.345678");

#ifdef __cpp_lib_to_chars
    float result = NAN;
    auto conv_ret = std::from_chars(sv.data(), (sv.data() + sv.size()), result);
    std::error_code ec = std::make_error_code(conv_ret.ec);
#else
    char *endp = nullptr;
    float result = std::strtof(sv.data(), &endp);
    std::error_code ec;
    if (errno == ERANGE) {
        ec = std::make_error_code(std::errc::result_out_of_range);
    }
#endif
    if(ec) {
        std::cerr << ec.message() << std::endl;
        return ec.value();
    }
    std::cout << "Float: " << result  << std::endl;
    return 0;
}
error: no matching function for call to 'from_chars(std::basic_string_view<char>::const_pointer, std::basic_string_view<char>::const_pointer, float&)'

Tried following code based on above error:

#if defined(CYGWIN_NT) || defined(AIX71) || defined(SUNOS)
    #include <iostream>
    using namespace std;
#elif defined(LINUX) || defined(HPUX11)
    #include <iostream.h>
#else
    #error handle iostream/iostream.h error.
#endif
#include <charconv>
int main()
{
    string_view s = "123.4";
    // Always better to initialize.
    float x = 0.0f;
    from_chars(s.data(), s.data() + s.size(), x);
    cout << x << endl;
    return 0;
}
// Sample compilation:
// echo g++ -Wall 73333331.cpp -D$(uname -s | sed "s/-[0-9].*.[0-9].*-[0-9].*//;") -std=c++20 -o ./a.out
// g++ -Wall 73333331.cpp -DCYGWIN_NT -std=c++20 -o ./a.out
// ./a.out
// 123.4

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM