使用 std::views 将 std::<string>vector 转换为 C++20 中的 std::string



我正在尝试将向量转换为字符串,并使用C++20(visual studio 19 v142上的MSVC,C++最新版本)连接。

std::vector<std::string> strings = { "1s","2s" };
auto view1 = strings | std::views::transform([](std::string num) {return std::format("{} ", num); }); // okay
auto view2 = strings | std::views::join; // okay
auto view3 = strings | std::views::transform([](std::string num) {return std::format("{} ", num); }) | std::views::join; // Compiler error  
//error C2678: binary '|': no operator found which takes a left-hand operand of type 'std::ranges::transform_view<std::ranges::ref_view<std::vector<std::string,std::allocator<std::string>>>,_Ty>' "

我知道我可以用actions在范围v3中优雅地完成它,但我不应该使用它。

有没有一种方法可以做到这一点,只需使用C++20标准库?

views::join的原始设计中,它不只是加入任何范围,它必须是范围的引用范围。

这起到了作用:

auto view2 = strings | views::join; // okay

因为stringsstring&的范围(其是对范围的引用)。

但事实并非如此:

auto view3 = strings | views::transform([](std::string num) {
return std::format("{} ", num)
})
| views::join; // Compiler error  

因为现在我们在join中处理一系列string(特别是prvalue字符串,这是函数返回的值)。这违反了限制。range-v3的CCD_ 7具有相同的约束。


然而,能够做到这一点是一个相当常见的用例。因此,最近针对C++20的一个缺陷是更改了views::join的设计,使其能够加入任何范围。这是P2328。libstdc++(gcc的标准库)已经实现了这一点,MSVC还没有,range-v3也没有(尽管我打开了一个PR)。因此,C++20的官方答案是:你所做的是正确的,你的库只是还没有实现它。


现在,range-v3的答案是引入一个缓存层:

auto view3 = strings | rv::transform([](std::string num) {
return std::format("{} ", num)
})
| rv::cache1
| rv::join;

cache1所做的是一次缓存一个元素,这将我们的prvalue范围string转换为lvalue范围string,这样join就可以成功地加入它。P2328的设计基本上是将其内部合并到join本身中,这样您就不必手动执行。但在此之前,您可以使用range-v3执行上述操作。在C++20中没有cache1,在C++23中也不会。

或者你可以使用凯西的破解。但也不要。

相关内容

  • 没有找到相关文章

最新更新