I'm facing an issue while attempting to populate a std::vector
with the results of std::views::split
in C++. Specifically, I can successfully construct a std::string
from the items of std::ranges::split_view
(as shown in the first loop of the code below), but I encounter difficulties when trying to use an iterator to create a std::vector
directly.
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>
int main()
{
std::string rg{ "1, 2, 3, 1, 2, 3, 4, 5, 6 "};
// Successful construction of std::string from std::ranges::split_view
for (const auto& subrange : rg | std::views::split('3'))
{
std::string value(subrange.begin(), subrange.end());
std::cout << value << '\n';
}
// Issue arises here when attempting to create std::vector
auto parts = rg | std::views::split('3');
auto asVector = std::vector<std::string>(parts.begin(), parts.end());
// The following loop results in a compilation error
for (const auto& subrange : asVector)
{
std::string value(subrange.begin(), subrange.end());
std::cout << value << '\n';
}
}
Compilation Error:
Error C2665 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string': no overloaded function could convert all the argument types
splitView C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.38.33030\include\xutility 241
I appreciate any insights or solutions to help me resolve this issue.
The value type of rg | std::views::split('3')
is subrange<string::iterator, string::iterator>
, and string
cannot be constructed through it, that is, is_constructible<string, subrange<string::iterator, string::iterator>
is false, so the compilation fails.
The ideal way is to use C++23 ranges::to
:
auto asVector = std::ranges::to<std::vector<std::string>>(parts);
which is applied recursively, so the string
is first constructed from the subrange
via (nested) ranges::to
, which in turn invokes its range constructor string(from_range_t, R&&)
, and then the vector
is subsequently constructed.
In C++20 you still need to manually convert the original subrange
to std::string
auto parts = rg | std::views::split('3')
| std::views::transform([](auto r) {
return std::string(r.data(), r.size());
});
auto asVector = std::vector(parts.begin(), parts.end());