Using this minimal .clang-format:
BasedOnStyle: LLVM
IndentWidth: 4
---
Language: Cpp
ColumnLimit: 120
UseTab: Never
AlignAfterOpenBracket: DontAlign
ContinuationIndentWidth: 8
I end up with code formatted like this:
#include <algorithm>
#include <string>
#include <vector>
int main() {
std::vector<std::string> vec;
vec.erase(std::remove_if(vec.begin(), vec.end(),
[](const std::string &) {
std::string x = "I'm here just to expand this block to keep it from collapsing";
return false;
}),
vec.end());
// the third argument, while invalid, doesn't affect clang-format.
// It exists to force the lambda to break to the next line. If it
// doesn't break, it ends up with slightly different, but still acceptable
// formatting. I need it on a new line to demonstrate the difference between
// a single function call, and calls to a function in the list of function
// params
std::remove_if(vec.begin(), vec.end(), imasuperlonginvalididentifiertopushthisblockfaaaarofftotheleft,
[](const std::string &) {
std::string x = "I'm here just to expand this block to keep it from collapsing";
return false;
});
}
My problem here is with the first block.
First of all, notice the second block. It indents the lambda, a wrapped arg, by 8 spaces. I'm fine with this. The first block, however, is bad:

Here's a numbered indent to show the problem:
vec.erase(std::remove_if(vec.begin(), vec.end(),
12345678[](const std::string &) {
std::string x = "I'm here just to expand this block to keep it from collapsing";
return false;
}),
vec.end());
Note how the indent is aligned to the start of std::remove_if. Because vec.erase( doesn't work out as 8, this means the entire block gets misaligned. I can deal with it for arguments, but the effects on multi-line lambda is a problem. This is how I want it to format:
vec.erase(std::remove_if(vec.begin(), vec.end(),
[](const std::string &) {
std::string x = "I'm here just to expand this block to keep it from collapsing";
return false;
}),
vec.end());
And numbered:
vec.erase(std::remove_if(vec.begin(), vec.end(),
1234567812345678[](const std::string &) {
std::string x = "I'm here just to expand this block to keep it from collapsing";
return false;
}),
vec.end());
And an image:

While writing this question, I've been a bit back and forth, because I'm not sure when it triggers. I cut down the column width to force std::remove_if to wrap:
std::remove(
std::remove_if( ...
[](...) { ...
it's suddenly fine, because remove_if has been aligned to an 8 block, which means the arguments are indented by 8 or 16 as well. However, with this code:
randomFunctionCall(functionCall2(9,
std::string{"I need args so I made some up. "
"clang-format should allow them"},
42, anotherlongidentifier, weeeeeeeeeee));
the arguments for the inner function arguments are fine. Well, kinda. They indent by 8 instead of 16, but I can live with that. (For the record, 16 comes from a continuation indent of 8, two levels deep, or 2 * 8 = 16). Now, watch what happens if I add another argument to the randomFunctionCall instead of adding to functionCall2:
randomFunctionCall(functionCall2(9,
std::string{"I need args so I made some up. "
"clang-format should allow them"},
42, anotherlongidentifier, weeeeeeeeeee),
randoarg);
The inner arguments align to the function call + 8 instead of the root function call + 16. So the misalignment happens, at least as far as I can tell, when there's a function call that takes a function call with arguments, but also has additional arguments beyond the function call.
When I have nested function calls (func(func2(severalArgsWithLongEnoughNamesToWrap), nonfuncarg)) with arguments, how do I get clang format to consider indentation from the start of the line, rather than from the start of the current function call? I'm aware I can use // clang-format off/on to locally enforce a non-standard style, but I would prefer not to.
I'm using Clang and clang-format 11.