如何配置Clang-Format实现等号后换行并对齐运算符
解决Clang-Format对C++20 Concept的格式化问题
问题背景
我正在配置Clang-Format,希望保留自己声明变量和Concept的代码风格。
期望的格式化样式
(开头制表符用⟶ 表示,空格用·表示)
template<typename T> concept my_concept = ⟶ ····std::destructible<T> ⟶ and std::copy_constructible<T> ⟶ and std::default_initializable<T> ⟶ and requires(T t) { ⟶ ⟶ { t.expression() }; ⟶ };
Clang-Format实际输出的样式
template<typename T> concept my_concept = std::destructible<T> and std::copy_constructible<T> ⟶ and std::default_initializable<T> and requires(T t) { ⟶ ⟶ ⟶ ⟶ ⟶ ⟶ ⟶ ⟶ ⟶ ⟶ ⟶ ⟶ ··{ t.expression() }; ⟶ ⟶ ⟶ ⟶ ⟶ ⟶ ⟶ ⟶ ⟶ ⟶ ⟶ ··};
待解决的三个问题
- Clang-Format用制表符对齐requires表达式
- Clang-Format对表达式进行二进制打包(bin packing)
- Clang-Format不在等号后换行,且不对齐
and关键字
当前的.clang-format配置
--- Language: Cpp # BasedOnStyle: Chromium AlignAfterOpenBracket: BlockIndent AccessModifierOffset: -4 AlignConsecutiveMacros: false AlignConsecutiveAssignments: false AlignConsecutiveBitFields: false AlignConsecutiveDeclarations: false AlignEscapedNewlines: Left AlignOperands: DontAlign AlignTrailingComments: false AllowAllArgumentsOnNextLine: true AllowAllConstructorInitializersOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: true AllowShortEnumsOnASingleLine: false AllowShortBlocksOnASingleLine: Always AllowShortCaseLabelsOnASingleLine: true AllowShortFunctionsOnASingleLine: Empty AllowShortLambdasOnASingleLine: All AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: true AlwaysBreakTemplateDeclarations: true BinPackArguments: false BinPackParameters: false BitFieldColonSpacing: Both AllowShortIfStatementsOnASingleLine: Never AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: true AlwaysBreakTemplateDeclarations: Yes BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Custom BraceWrapping: AfterCaseLabel: false AfterClass: false AfterControlStatement: Never AfterEnum: false AfterFunction: false AfterNamespace: false AfterStruct: false AfterUnion: false AfterExternBlock: false BeforeCatch: false BeforeElse: false BeforeLambdaBody: false BeforeWhile: false IndentBraces: false SplitEmptyFunction: false SplitEmptyRecord: false SplitEmptyNamespace: false #BreakAfterAttributes: Always BreakBeforeConceptDeclarations: Always BreakBeforeTernaryOperators: true BreakConstructorInitializers: AfterColon BreakInheritanceList: AfterColon BreakStringLiterals: true ColumnLimit: 120 CompactNamespaces: false ConstructorInitializerIndentWidth: 4 Cpp11BracedListStyle: true BreakAfterJavaFieldAnnotations: true CommentPragmas: '^ IWYU pragma:' ConstructorInitializerAllOnOneLineOrOnePerLine: false ContinuationIndentWidth: 4 DeriveLineEnding: false DerivePointerAlignment: false DisableFormat: false EmptyLineAfterAccessModifier: Never EmptyLineBeforeAccessModifier: Always ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH IncludeBlocks: Regroup IncludeCategories: - Regex: 'define.hpp' Priority: 5 - Regex: '^<[a-z_]+>' Priority: 4 - Regex: '^<.+\.h(pp)?>' Priority: 3 - Regex: '^<.*' Priority: 2 - Regex: '.*' Priority: 1 IncludeIsMainRegex: '' IncludeIsMainSourceRegex: '' IndentAccessModifiers: false IndentCaseLabels: true IndentCaseBlocks: false IndentGotoLabels: false IndentExternBlock: IndentPPDirectives: BeforeHash IndentExternBlock: Indent IndentWidth: 4 IndentWrappedFunctionNames: false InsertBraces: true #InsertNewlineAtEOF: true InsertTrailingCommas: Wrapped JavaScriptQuotes: Double JavaScriptWrapImports: true LambdaBodyIndentation: Signature KeepEmptyLinesAtTheStartOfBlocks: false MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: All ObjCBinPackProtocolList: Never ObjCBlockIndentWidth: 2 ObjCBreakBeforeNestedBlockParam: true ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: true PackConstructorInitializers: NextLine PenaltyBreakAssignment: 2 PenaltyBreakBeforeFirstCallParameter: 1 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left QualifierAlignment: Custom QualifierOrder: ['static', 'inline', 'constexpr', 'type', 'const', 'volatile'] RawStringFormats: - Language: Cpp Delimiters: - cc - CC - cpp - Cpp - CPP - 'c++' - 'C++' CanonicalDelimiter: '' BasedOnStyle: google - Language: TextProto Delimiters: - pb - PB - proto - PROTO EnclosingFunctions: - EqualsProto - EquivToProto - PARSE_PARTIAL_TEXT_PROTO - PARSE_TEST_PROTO - PARSE_TEXT_PROTO - ParseTextOrDie - ParseTextProtoOrDie - ParseTestProto - ParsePartialTestProto CanonicalDelimiter: '' BasedOnStyle: google ReferenceAlignment: Left #RemoveSemicolon: true RequiresClausePosition: SingleLine #RequiresExpressionIndentation: OuterScope SeparateDefinitionBlocks: Always ShortNamespaceLines: 8 ReflowComments: true SortIncludes: true SortUsingDeclarations: true SpaceAfterCStyleCast: true SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: false SpaceAroundPointerQualifiers: Before SpaceBeforeAssignmentOperators: true SpaceBeforeCaseColon: false SpaceBeforeCpp11BracedList: false SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatementsExceptForEachMacros SpaceBeforeRangeBasedForLoopColon: true SpaceBeforeSquareBrackets: false SpaceInEmptyBlock: false SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 4 SpacesInAngles: false SpacesInConditionalStatement: false SpacesInContainerLiterals: false SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: c++20 StatementMacros: - Q_UNUSED - QT_REQUIRE_VERSION TabWidth: 4 IndentWidth: 4 UseCRLF: false UseTab: AlignWithSpaces WhitespaceSensitiveMacros: - STRINGIZE - PP_STRINGIZE - BOOST_PP_STRINGIZE ...
解决方案
针对三个问题,修改以下配置项:
1. 解决requires表达式对齐问题
取消注释并设置RequiresExpressionIndentation: OuterScope,让requires块内的内容仅缩进一级,而非对齐到requires关键字的位置。
2. 禁用二进制打包
确保BinPackArguments和BinPackParameters已设为false,同时添加BinPackOperands: false禁止表达式的二进制打包行为。
3. 实现等号后换行并对齐and关键字
- 将
BreakBeforeBinaryOperators从NonAssignment改为All,让每个and操作符都换行显示 - 设置
BreakAfterEquals: Always,强制在等号后换行 - 将
AlignOperands从DontAlign改为Align,让and关键字对齐到同一列
修改后的关键配置片段
# ... 其他配置保持不变 ... BreakBeforeBinaryOperators: All BreakAfterEquals: Always AlignOperands: Align BinPackOperands: false RequiresExpressionIndentation: OuterScope # ... 其他配置保持不变 ...
验证效果
修改后,Clang-Format会输出与期望一致的格式:
template<typename T> concept my_concept = std::destructible<T> and std::copy_constructible<T> and std::default_initializable<T> and requires(T t) { { t.expression() }; };
内容的提问来源于stack exchange,提问作者Guillaume Racicot
相关产品推荐
相关产品推荐

