12

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

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Ben
  • 9,184
  • 1
  • 43
  • 56
  • This to me is just yet another in an endless series of examples of: formatting usually doesn't matter, but when it does, clang-format does it wrong. – Barry Feb 01 '22 at 16:01
  • I've generally been pleased with it, but there are context-dependent things I wish I could control... like this, or like c'tors for 4x4 matrices taking 16 arguments: I wish it could line-break them with aligned commas. – Ben Feb 01 '22 at 22:41
  • Since my above comment, I've gotten in the habit of using empty comments (`//`) to force line breaks for things like 4x4 matrices. The commas aren't aligned, but it's a practical solution. – Ben Jul 26 '22 at 12:15

1 Answers1

1

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.

FeignClaims
  • 193
  • 8