I want to split a string by a token with std::views::split
, and for each retrieved substring invoke the std::from_chars
function.
Here is an MRE (https://godbolt.org/z/1K71qo9s4) that compiles successfully on GCC but fails to compile on MSVC:
#include <iostream>
#include <ranges>
#include <string>
#include <charconv>
int main()
{
std::string source{"10%15%20%35"};
for ( auto i : source | std::views::split('%') )
{
int x;
std::from_chars( i.begin().base(), i.end().base(), x );
std::cout << x << ' ';
}
}
What strange is that according to cppreference, the behavior of std::views::split
was changed in P2210R2, providing base()
function which effect is
Equivalent to
return cur_
Then, according to compiler support page, the P2210R2
is supported in MSVC since 19.31, so the example should work.
If this were working how you think it does, i.begin().base()
should be a std::string::iterator
, which has to be const char*
(or at least convertible to a const char*
) to pass to std::from_chars
.
Looks like libstdc++ also doesn't implement this properly either, and i.begin()
is returning a std::string::iterator
instead of a std::ranges::views::split_view<std::string>::iterator
. It just so happens that libstdc++'s std::string::iterator
has a function called base()
that returns a pointer.
You have to get a const char*
pointer anyways, which you can do with std::to_address
:
std::from_chars( std::to_address(i.begin()), std::to_address(i.end()), x );
Or something like:
std::from_chars( std::ranges::data(i), std::ranges::data(i) + std::ranges::size(i), x );
// Or, since span is constructible from ranges
for (std::span<const char> i : source | std::views::split('%')) {
std::from_chars( i.data(), i.data() + i.size(), x );