Tweaking clang-format for C++20 ranges pipelines

Viewed 205

C++20 (and 23 with std::ranges::to<T>()) makes idiomatic the use of operator| to make a pipeline of transformations such as this:

    return numbers 
        | std::views::filter([](int n) { return n % 2 == 0; })
        | std::views::transform([](int n) { return n * 2; })
        | std::ranges::to<std::vector>();

With my project's current .clang-format, that looks something like

    return numbers | std::views::filter([](int n) { return n % 2 == 0; }) |
           std::views::transform([](int n) { return n * 2; }) | std::ranges::to<std::vector>();

which I find pretty hard to read. If I set BreakBeforeBinaryOperators: All I get

    return numbers | std::views::filter([](int n) { return n % 2 == 0; })
           | std::views::transform([](int n) { return n * 2; }) | std::ranges::to<std::vector>();

which is better, but I'd really like the original version with one pipeline operation on each line.

I can adjust the column limit, but that is a major change and also starts to line-break my lambdas, which I don't like:

    return numbers | std::views::filter([](int n) {
               return n % 2 == 0;
           })
           | std::views::transform(
               [](int n) { return n * 2; })
           | std::ranges::to<std::vector>();

I can manually use empty comments to force a newline:

    return numbers                                                //
           | std::views::filter([](int n) { return n % 2 == 0; }) //
           | std::views::transform([](int n) { return n * 2; })   //
           | std::ranges::to<std::vector>();

but again, not ideal knowing that pipelines will be pretty common. Am I missing settings? Or is this more of a feature request I should direct to clang-format, like "Add an option so when more than n operator| appears in an expression, put each subexpression on its own line."

0 Answers
Related