Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tweaking clang-format for C++20 ranges pipelines

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."

like image 480
Ben Avatar asked Dec 18 '25 16:12

Ben


1 Answers

There's a feature request for AllowBreakingBinaryOperators. Before the feature completes, only compromise can be made.

  1. As you've said, use // comments to force line breaks.
  2. use clang-format off/on to disable clang-format and format it yourself.

Here's a more complex solution which combines both:

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

First, use // to split and then clang-format the code.

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

Next, remove //, use clang-format off/on to disable clang-format.

void function() {
  // clang-format off
  return numbers
         | std::views::filter([](int n) { return n % 2 == 0; })
         | std::views::transform([](int n) { return n * 2; })
         | std::views::take(3)
         | std::ranges::to<std::vector>();
  // clang-format on
}

As for matrix, the option AlignArrayOfStructures might help.

like image 105
FeignClaims Avatar answered Dec 21 '25 07:12

FeignClaims



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!