std::views::split
の結果をそのままto<std::vector>
に渡してコンパイルエラーに悩まされたのでメモとして。
結論としてstd::views::split
の戻り値をstd::ranges::to
でSTLコンテナに変換するとき、手前で各要素をstd::wstring
やstd::wstring_view
に変換する必要があります。std::views::split
戻り値の各要素はstd::ranges::subrange
型で文字列型への直接変換が実装されていないからです。
下記にサンプルコードを示します。丸ごと補助関数にまとめたり、std::wstring
やstd::wstring_view
への変換だけ補助関数にしても良いかもしれません。
#include <ranges> #include <string> #include <vector> #include <iostream> using namespace std::string_view_literals; int wmain() { auto s1{ L"ABC\0DEF\0GHI\0\0"sv }; // std::vector<std::wstring>の作成 auto sv1{ std::views::split(s1, L'\0') | std::views::transform([](const auto& sr) {return std::wstring(std::ranges::begin(sr), std::ranges::end(sr)); }) | std::ranges::to<std::vector>() }; // std::vector<std::wstring_view>の作成 auto svv1{ std::views::split(s1, L'\0') | std::views::transform([](const auto& sr) {return std::wstring_view(sr); }) | std::ranges::to<std::vector>() }; return -1; }
std::views::split
の動作は次のコードで確認できます。MSVC 2022であればstd::ranges::split_view
のclass _Iterator::value_type
でsubrange
が明示されているのでSTLソースコードからも確認できます。
#include <ranges> #include <string> #include <vector> #include <iostream> using namespace std::string_view_literals; int wmain() { auto s1{ L"ABC\0DEF\0GHI\0\0"sv }; for (const auto& i : std::views::split(s1, L'\0')) { // iはstd::ranges::subrange型です。 // const std::ranges::subrange<std::_String_view_iterator<std::char_traits<wchar_t>>,std::_String_view_iterator<std::char_traits<wchar_t>>,1> & // デバッグウィンドウに表示するための操作 auto j = i; } for (const auto& i : std::views::split(s1, L'\0')) { // std::ranges::subrangeはレンジなのでstd::wstring_viewに変換できます。 std::wstring_view sv(i); // std::wstringはレンジからの作成に未対応なのでエラーになります。 //std::wstring sv(i); } // 以下をコメントアウトするとコンパイルエラーになります。 // std::views::splitの戻り値型std::ranges::subrangeはstd::vectorの要素にできません。 // 下記のようにtransformでstd::wstring_viewやstd::wstringへ変換すれば解決します。 //for (const auto& i : std::views::split(s1, L'\0') | std::ranges::to<std::vector>()) //{ // std::wstring_view sv(i); //} // std::wstringはレンジからの作成に未対応です。イテレータペアから作成します。 auto sv1{ std::views::split(s1, L'\0') | std::views::transform([](const auto& sr) {return std::wstring(std::ranges::begin(sr), std::ranges::end(sr)); }) | std::ranges::to<std::vector>() }; // std::wstring_viewはレンジからの作成に対応しています。記述量が減ります。 // ただし、元の文字列がリテラルでない場合はメモリが解放されると無効になります。 auto svv1{ std::views::split(s1, L'\0') | std::views::transform([](const auto& sr) {return std::wstring_view(sr); }) | std::ranges::to<std::vector>() }; return -1; }
参考