Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you return range based views from functions in c++2a?

Tags:

c++

c++20

Now I can't find any compiler yet that has this support for the "one ranges proposal" so this is more of an academic question. I'm curious if the following will work like I expect

#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;
   }
}

with an expected output of

5
4
3
2
1

The question has to do with the ownership semantics of the range adaptors. I say I want to move a and then wrap it with a view. What is expected to happen?

  1. Not compile.
  2. Compile but maybe crash with a memory corruption
  3. Work as expected
like image 306
bradgonesurfing Avatar asked Jan 25 '23 21:01

bradgonesurfing


2 Answers

Can you return range based views from functions in c++2a?

You can.

But returning view to a local variable or temporary would be useless since behaviour of accessing through the view to the destroyed object would be undefined. Same as returning an iterator, pointer or a reference.

I say I want to move a and then wrap it with a view. What is expected to happen?

At least going by what ranges-v3 does, it static asserts that the operand is an lvalue, which fails the compilation.

like image 166
eerorika Avatar answered Jan 30 '23 14:01

eerorika


Views in range-v3/C++20 ranges are non-owning by design. reverse is always going to be non-owning, so returning that directly to a local range is going to dangle. There's no "owning view" concept in the library.

You can do it by hand though, by writing a custom type that has both the container and the view as members:

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)};
}

This could probably be generalized.

like image 43
Barry Avatar answered Jan 30 '23 12:01

Barry