Search code examples
c++std-rangesc++23

Right associativity for `std::views`


Left associativity is already guaranteed by C++ core semantics: R|V1|V2 is parsed as (R|V1)|V2). What if the coder wants to explicitly change the order of operations to R|(V1|V2)? Is this possible under C++23? The reason behind the question is that it simplifies defining custom range adapters:

auto myV=V1|V2|V3;
for(auto& x:R1|myV)/*..*/;
for(auto& x:R2|myV)/*..*/;

All this needs seems to be a properly constraint overload on std::views::operator|; Does such overload exist? If not, will it be added? If not, what's the rationale behind it?


Solution

  • What if the coder wants to explicitly change the order of operations to R|(V1|V2)?

    Then they can just write that. That is a valid expression.

    The way that range adaptor closure objects are defined, there are two equivalences (C and D here are range adaptor closure objects and R is a range):

    • R | C is equivalent to C(R)
    • R | (C | D) is equivalent to R | C | D

    The latter is the property that lets you write what you're asking about. For instance:

    auto flat_map = [](auto f){
        return views::transform(f) | views::join;
    };
    
    vector<int> v = {1, 2, 3};
    auto w = v | flat_map([](int i){ return vector<int>(i, i); }
    

    And here w becomes the range [1, 2, 2, 3, 3, 3].