c++std-ranges

How to define a type for a ranges::view without defining it initially?


I need to specify different ranges::views depending upon a variable. Such as:

#include <ranges>
#include <vector>

auto main() -> int
{
    std::vector<double> xs = { 1.0, 2.0, 3.0, 4.0, 5.0 };
    auto x = int(0);

    auto vi;

    if(x == 0)
        vi = xs | std::ranges::views::all;
    else
        vi = xs | std::ranges::views::drop(2); 
}

but the problem is auto can't determine a type so I need to define it as I've defined the int type for x. (i.e., auto x = int(0);).

How do I do this for a view?


Solution

  • Normally, you would want to avoid this altogether by not declaring vi until it can be inferred properly, which is not as constraining as you might think:

    #include <ranges>
    #include <vector>
    #include <iostream>
    
    template<typename RangeT>
    void foo(const RangeT& vi) {
        for(auto & v: vi) {
            std::cout << v << "\n";
        }
    }
    
    auto main() -> int
    {
        std::vector<double> xs = { 1.0, 2.0, 3.0, 4.0, 5.0 };
        auto x = int(0);
    
        if(x == 0) {
            auto vi = xs | std::ranges::views::all;
            foo(vi);
        }
        else {
            auto vi = xs | std::ranges::views::drop(2); 
            foo(vi);
        }
    }
    

    That being said, in case anyone lands here and has really painted themselves in a corner, it's still worth answering the question as asked.

    You can use decltype() to identify the types that will be used, and then use std::variant<> to make vi a type that can hold either of them:

    #include <ranges>
    #include <vector>
    #include <variant>
    #include <iostream>
    
    auto main() -> int
    {
        std::vector<double> xs = { 1.0, 2.0, 3.0, 4.0, 5.0 };
        auto x = int(0);
    
        using vi_all = decltype(xs | std::ranges::views::all);
        using vi_drop_2 = decltype(xs | std::ranges::views::drop(2));
        std::variant<vi_all, vi_drop_2> vi;
    
        if(x == 0)
            vi = xs | std::ranges::views::all;
        else
            vi = xs | std::ranges::views::drop(2); 
    
    
        std::visit([](auto& vi){
            for(auto& v: vi) {
                std::cout << v << "\n";
            }
        }, vi);
    }