如何配置Clang-Format避免短Lambda被拆分为两行(保留单行Lambda)
升级到Clang-Format 15.0.1后,中等长度的Lambda出现了不符合预期的格式:Lambda头(捕获+参数)因长度换行,但Lambda体与大括号挤在同一行。希望保留能完整放在一行的单行Lambda,同时让换行后的Lambda体遵循Allman风格(大括号单独起行,代码缩进),与if语句的格式保持一致。
格式示例
当前不想要的格式
const auto mediumLambda = [some, args, here](More arguments) { return doSomething(some, args, here, arguments); };
期望格式
const auto mediumLambda = [some, args, here](More arguments) { return doSomething(some, args, here, arguments); };
正常格式的参考示例
// 可单行的Lambda(希望保留) auto shortLambda= []() { doSomething(); }; // 多行Lambda(格式正常) const auto longLambda= [some, args, here](Are here) { auto result =doSomething(some, args, here, arguments); return result; }; // if语句的目标格式(与Lambda期望对齐) if (condition) { doWhatever(); }
当前相关配置
# Basic Language : Cpp Standard : c++20 ColumnLimit : '110' # Tabs TabWidth : '3' IndentWidth : '3' UseTab : Never # Braces/Parens (Allman style) BreakBeforeBraces : Custom BraceWrapping: AfterCaseLabel: true AfterClass: true AfterControlStatement: true AfterEnum: true AfterFunction: true AfterNamespace: true AfterObjCDeclaration: true AfterStruct: true AfterUnion: true AfterExternBlock: true BeforeCatch: true BeforeElse: true BeforeLambdaBody: true IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true Cpp11BracedListStyle : true SpaceBeforeParens : ControlStatements SpacesInParentheses : false SpaceInEmptyParentheses : false # Functions AlignAfterOpenBracket : Align AllowShortBlocksOnASingleLine : false AllowShortFunctionsOnASingleLine : Inline BinPackArguments : true BinPackParameters : true AllowAllParametersOfDeclarationOnNextLine : true IndentWrappedFunctionNames : false AlwaysBreakAfterReturnType : None AlwaysBreakAfterDefinitionReturnType : None # Lambdas AllowShortLambdasOnASingleLine : All
问题原因与解决方案
这是Clang-Format 15中AllowShortLambdasOnASingleLine: All的行为变化导致的:该选项现在会允许即使Lambda头换行,只要Lambda体较短,就会将体与大括号放在同一行,直接覆盖了AllowShortBlocksOnASingleLine: false的设置。
目前没有完美的配置能同时满足「保留单行Lambda」和「头换行时强制Lambda体按Allman风格格式化」两个需求,但可以选择以下折中方案:
方案1:接受所有Lambda多行格式
将AllowShortLambdasOnASingleLine改为None,所有Lambda都会采用Allman风格,包括原本可单行的Lambda:
AllowShortLambdasOnASingleLine : None
效果:
// 原本的单行Lambda变为多行 auto shortLambda= []() { doSomething(); }; // 中等长度Lambda符合预期 const auto mediumLambda = [some, args, here](More arguments) { return doSomething(some, args, here, arguments); };
方案2:仅允许inline场景的单行Lambda
将AllowShortLambdasOnASingleLine改为Inline,只有作为inline表达式的Lambda(比如函数参数)会保留单行,赋值给变量的Lambda无论长短都会采用Allman风格:
AllowShortLambdasOnASingleLine : Inline
效果:
// 赋值给变量的Lambda变为多行 auto shortLambda= []() { doSomething(); }; // 作为函数参数的Lambda保留单行 std::for_each(v.begin(), v.end(), [](int x) { std::cout << x; });
方案3:降级到Clang-Format 14
Clang-Format 14及更早版本中,AllowShortLambdasOnASingleLine: All仅允许整个Lambda能放在一行时使用单行格式,当头换行时,Lambda体会自动遵循Allman风格,与你的预期完全一致。
内容的提问来源于stack exchange,提问作者jtooker

