C++ 能否从c+;中的函数返回基于范围的视图+;2a?

C++ 能否从c+;中的函数返回基于范围的视图+;2a?,c++,c++20,C++,C++20,现在我还找不到任何编译器支持,所以这更像是一个学术问题。我很好奇下面的工作是否会像我预期的那样 #include <iostream> #include <vector> #include <ranges> auto Foo (){ std::vector<int> a = {1,2,3,4,5}; return std::move(a) | std::reverse; } int main(){ for(auto a

现在我还找不到任何编译器支持,所以这更像是一个学术问题。我很好奇下面的工作是否会像我预期的那样

#include <iostream>
#include <vector>
#include <ranges>

auto Foo (){
    std::vector<int> a = {1,2,3,4,5};
    return std::move(a) | std::reverse;
}


int  main(){
   for(auto a : Foo()){
       std::cout << a << std::endl;
   }
}
这个问题与范围适配器的所有权语义有关。我说我想移动a,然后用视图将其包装起来。预计会发生什么

  • 不编译
  • 编译,但可能会因内存损坏而崩溃
  • 如期工作
  • 能否从c++2a中的函数返回基于范围的视图

    你可以

    但将视图返回到局部变量或临时变量将是无用的,因为通过视图访问被破坏对象的行为将是未定义的。与返回迭代器、指针或引用相同

    我说我想移动一个视图,然后用一个视图将其包裹起来。预计会发生什么


    至少从ranges-v3的作用来看,它静态断言操作数是一个左值,编译失败。

    range-v3/C++20范围中的视图不是设计所拥有的
    reverse
    始终是非所有权的,因此直接将其返回到本地范围将是悬而未决的。图书馆中没有“拥有视图”的概念

    不过,您可以手动完成,方法是编写一个自定义类型,该类型将容器和视图都作为成员:

    auto Foo() {
        std::vector<int> a = {1, 2, 3, 4, 5};
    
        struct X {
            std::vector<int> a;
            decltype(a | views::reverse) view = a | views::reverse;
    
            // plus copy/move ctor/assignment
    
            auto begin() { return view.begin(); }
            auto end()   { return view.end(); }
        };
        return X{std::move(a)};
    }
    
    auto-Foo(){
    向量a={1,2,3,4,5};
    结构X{
    std::载体a;
    decltype(a | views::reverse)view=a | views::reverse;
    //加上复制/移动/分配
    自动开始(){返回视图。开始();}
    自动结束(){return view.end();}
    };
    返回X{std::move(a)};
    }
    

    这可能是广义的

    您不能在右值上使用视图,因此这将在编译时失败。这是一个奇怪的限制。我有自己的基于范围的库(公司所有,因此无法共享:()但它将右值和左值作为两种不同的情况处理。左值是使用非拥有的引用来持有的。右值是通过移入值并拥有它来持有的。我希望在某个时候迁移到std::range。恐怕运气不好。我真的无法向您指出它背后的确切措辞或推理,但我记得在我短暂的遭遇中与Eric Niebler(range-v3的作者)合作,他说,这意味着范围不适用于右值源:我的技巧是我总是通过值而不是引用来存储LHS。但是管道操作符区分右值和左值。右值被移入。左值用
    boost::make_iterator_range
    包装,它本身是通过值存储的。本质上是ref wrapper。这让我知道了我是如何做到的。如果视图不是按引用存储,而是总是按值存储,那么range-v3会不会受到性能的影响。然后将由管道操作符将左值包装到引用包装中。间接性会影响性能吗?@bradgonessurfing当然。为什么视图会复制某些内容?Fo关注性能,关注意图。视图从不拥有任何东西。如果从函数返回视图,并且该视图的源范围是当前范围实现的局部变量,则无法返回该视图。例如,简单的小示例编译,然后在运行时分段出错。如果尝试将向量移动到它无法编译的视图中。@bradgonesurfing,这与我所说的有什么关系?这是一个通过引用返回本地对象的示例。这是一个坏主意。我们都知道。选择的视图是轻量级的,复制成本低-这就是后果。@Fureish您已经说过了“视图从不拥有任何东西”我刚才问的问题是“为什么”。我给出了一个函数返回视图的示例,我知道它会出错并知道原因。解决方法是使用
    std::move(vi)
    它会告诉操作符移动局部变量。类似,但这不会编译。我的问题是
    为什么不支持它
    这是一个有用的用例。“视图”的定义特征"事实上,我不确定它现在是什么-持续时间破坏?但是视图的惰性是有代价的,因此,如果您需要吞食底层容器,那么视图可能是错误的选择,您需要的是操作。但是复制这种类型是危险的。您可能需要一个移动构造函数,以便在pip中执行此操作eline矢量没有被复制。@bradgonesurfing是的,重复数据消除程序已经做了此评论,我不想写出来,所以我只留下了一条评论。我将此标记为解决方案,因为它看起来像是支持我的用例所需的解决方案。如果解决方案有点充实,并检查健壮性问题,那就太好了ed.如果你不介意的话,我可能会晚一点开车过来,然后再做。我现在想做的是
    return std::move(v)| views::own()| views::reverse()
    auto Foo() {
        std::vector<int> a = {1, 2, 3, 4, 5};
    
        struct X {
            std::vector<int> a;
            decltype(a | views::reverse) view = a | views::reverse;
    
            // plus copy/move ctor/assignment
    
            auto begin() { return view.begin(); }
            auto end()   { return view.end(); }
        };
        return X{std::move(a)};
    }