一些C++20的ranges视图与std::copy不兼容。

3
在下面的代码中,目前无法编译。但是将std::views::take(2)替换为std::views::drop_while,代码就可以编译。我明白take_viewdrop_while视图执行不同的操作,但无论如何,如果我想要取出一些元素或者丢弃一些元素,我仍然应该能够将它们复制到容器中。
#include <ranges>
#include <vector>
#include <iostream>
#include <unordered_map>
using namespace std;

int main()
{
    //std::views::drop_while([](const int val){return val < 9;}) |

    vector v{1,2,3,4,5,6,7,4,8,9};   
    std::ranges::take_view res = v | std::views::filter([](const int val){return val %2 == 0;}) | std::views::transform([](const int val){return val*3;}) 
    |  std::views::take(2);
    decltype(v) filtered;
    std::copy(res.begin(),res.end(),std::back_inserter(filtered));
    for (const auto val : filtered)
    {
        std::cout << "val: " << val << '\n';
    }


    return 0;
}

在网上试图寻找解释。 编辑: 错误:
main.cpp: 在函数 'int main()' 中:main.cpp:23:14: 错误:没有找到与 'copy(std::counted_iterator<...>, main()::..., std::ranges::take_view<...>, main()::..., main()::...>::_Sentinel, std::back_insert_iterator<...>)' 匹配的函数 23 | std::copy(res.begin(),res.end(),std::back_inserter(filtered)); | ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 在文件中从 /usr/include/c++/11/bits/char_traits.h:39 包含,从 /usr/include/c++/11/string:40 包含,从 /usr/include/c++/11/bits/locale_classes.h:40 包含,从 /usr/include/c++/11/bits/ios_base.h:41 包含,从 /usr/include/c++/11/streambuf:41 包含,从 /usr/include/c++/11/bits/streambuf_iterator.h:35 包含,从 /usr/include/c++/11/iterator:66 包含,从 /usr/include/c++/11/ranges:43 包含,从 main.cpp:9 包含: /usr/include/c++/11/bits/stl_algobase.h:611:5: 注意:候选函数: 'template constexpr _OI std::copy(_II, _II, _OI)' 611 | copy(_II __first, _II __last, _OI __result) | ^~~~ /usr/include/c++/11/bits/stl_algobase.h:611:5: 注意: 模板参数推断/替换失败: main.cpp:23:14: 注意:对于参数 '_II' 推断出的冲突类型 ('std::counted_iterator<...>, main()::..., main()::...>::_Iterator' 和 'std::ranges::take_view<...>, main()::..., main()::...>::_Sentinel') 23 | std::copy(res.begin(),res.end(),std::back_inserter(filtered)); | ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 在文件中从 /usr/include/c++/11/iterator:66 包含,从 /usr/include/c++/11/ranges:43 包含,从 main.cpp:9 包含: /usr/include/c++/11/bits/streambuf_iterator.h:325:5: 注意:候选函数: 'template::__value, std::ostreambuf_iterator<_CharT> >::__type std::copy(std::istreambuf_iterator<_CharT>, std::istreambuf_iterator<_CharT>, std::ostreambuf_iterator<_CharT>)' 325 | copy(istreambuf_iterator<_CharT> __first, | ^~~~ /usr/include/c++/11/bits/streambuf_iterator.h:325:5: 注意: 模板参数推断/替换失败: main.cpp:23:14: 注意: 'std::counted_iterator<...>, main()::..., main()::...>::_Iterator' 不是派生自 'std::istreambuf_iterator<_CharT>' 23 | std::copy(res.begin(),res.end(),std::back_inserter(filtered)); | ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1
请包含编译错误。 - undefined
5
为什么不直接使用ranges::copy呢?将基于C++17迭代器系统的算法与C++20迭代器混合使用通常是一个合适的选择。在你的情况下尤其如此,因为res是一个常规范围,这意味着它的begin()end()返回不同类型,这也是为什么存在views::common的原因。 - undefined
3
为什么你不加入#include <algorithm>呢?如果加入的话对我来说是有效的。 - undefined
@Quimby 已编辑,有错误 - undefined
@DeborahC 对我来说(GCC 13.1.0),它定义了std::copy的重载,可以实现你所需的功能。 - undefined
显示剩余3条评论
1个回答

3
范围res不是通用范围的模型,即其begin()end()具有不同的类型。
简单的解决方案是使用算法的范围版本。
    std::ranges::copy(res, std::back_inserter(filtered));

如果你真的需要开始和结束(对于一个尚未转换为范围的函数,比如std::accumulate()),那么我们需要将其转换为一个公共范围。
    auto common_res = res | std::views::common;
    std::copy(common_res.begin(), common_res.end(), std::back_inserter(filtered));

完整的程序:
#include <algorithm>
#include <iostream>
#include <ranges>
#include <vector>

int main()
{
    std::ranges::take_view res = std::views::iota(1,10)
        | std::views::filter([](const int val){return val %2 == 0;})
        | std::views::transform([](const int val){return val*3;})
        | std::views::take(2);

    std::vector<int> filtered;
    std::ranges::copy(res, std::back_inserter(filtered));
    for (const auto val : filtered) {
        std::cout << "val: " << val << '\n';
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接