clang-format: как сохранить каждый элемент списка инициализаторов конструктора в отдельной строке

У меня есть такой класс C ++:

class A {
public:
    A() :
        m_a(someValue1),
        m_b(someValue2),
        m_c(someValue3)
    {
    }

    // .... other class members

private:
    A m_a;
    B m_b;
    C m_c;
};

После форматирования этого кода с помощью clang-формата я получаю:

class A {
public:
    A() :
        m_a(someValue1), m_b(someValue2), m_c(someValue3)
    {
    }

    // .... other class members

private:
    A m_a;
    B m_b;
    C m_c;
};

Т.е. Список инициализаторов в конструкторе был отформатирован в одну строку до тех пор, пока не будет достигнута разрешенная максимальная длина строки.

Мой вопрос в том, как сообщить clang-format, чтобы каждый элемент оставался в отдельной строке, как это было в моем исходном коде до форматирования? Я не нашел подходящего параметра. Я попытался установить параметр AllowShortBlocksOnASingleLine, который мне показался наиболее подходящим, как true, так и false, но это не повлияло на это. Так может кто-нибудь подсказать, как реализовать такое форматирование?

Вот мой формат .clang:

BasedOnStyle: Google
AccessModifierOffset: '-4'
AlignAfterOpenBracket: DontAlign
AlignConsecutiveAssignments: 'false'
AlignConsecutiveDeclarations: 'false'
AlignEscapedNewlines: Left
AlignOperands: 'true'
AlignTrailingComments: 'false'
AllowAllParametersOfDeclarationOnNextLine: 'true'
AllowShortBlocksOnASingleLine: 'true'
AllowShortCaseLabelsOnASingleLine: 'true'
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: 'true'
AllowShortLoopsOnASingleLine: 'false'
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: 'false'
AlwaysBreakTemplateDeclarations: 'true'
BinPackArguments: 'true'
BinPackParameters: 'true'
BreakAfterJavaFieldAnnotations: 'true'
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BraceWrapping:
AfterFunction: true
SplitEmptyFunction: true
BreakBeforeInheritanceComma: 'false'
BreakBeforeTernaryOperators: 'true'
BreakConstructorInitializers: AfterColon
BreakStringLiterals: 'true'
ColumnLimit: '100'
CompactNamespaces: 'false'
ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
ConstructorInitializerIndentWidth: '4'
ContinuationIndentWidth: '8'
Cpp11BracedListStyle: 'true'
DerivePointerAlignment: 'false'
DisableFormat: 'false'
ExperimentalAutoDetectBinPacking: 'false'
FixNamespaceComments: 'true'
IncludeBlocks: Preserve
IndentCaseLabels: 'true'
IndentPPDirectives: None
IndentWidth: '4'
IndentWrappedFunctionNames: 'false'
JavaScriptQuotes: Double
JavaScriptWrapImports: 'true'
KeepEmptyLinesAtTheStartOfBlocks: 'false'
NamespaceIndentation: None
PointerAlignment: Left
ReflowComments: 'false'
SortIncludes: 'true'
SortUsingDeclarations: 'true'
SpaceAfterCStyleCast: 'true'
SpaceAfterTemplateKeyword: 'false'
SpaceBeforeAssignmentOperators: 'true'
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: 'false'
SpacesBeforeTrailingComments: '2'
SpacesInAngles: 'false'
SpacesInCStyleCastParentheses: 'false'
SpacesInContainerLiterals: 'false'
SpacesInParentheses: 'false'
SpacesInSquareBrackets: 'false'
Standard: Cpp11
TabWidth: '4'
UseTab: Never

ОБНОВЛЕНИЕ: есть опция в формате clang под названием «ConstructorInitializerAllOnOneLineOrOnePerLine», описанная следующим образом: «Если инициализаторы конструктора не помещаются в строку, поместите каждый инициализатор в отдельную строку». Однако он по-прежнему не выполняет то, что я хочу, потому что он перемещает инициализатор на новую строку только в том случае, если он не соответствует пределу столбца. Похоже, что нет способа заставить clang-format помещать последующий инициализатор в следующую строку, даже если предел столбца не достигнут. Было бы неплохо, если бы вышеупомянутый параметр превратился в перечисление с дополнительным значением, заставляющим поместить инициализатор на следующую строку, даже если предел столбца не достигнут.


person ivan.ukr    schedule 28.06.2019    source источник
comment
В основном тот же вопрос: stackoverflow.com/questions/ 53797967 /   -  person stijn    schedule 25.04.2021


Ответы (4)


Я почти уверен, что это ошибка / недостаток clang-формата. Проблема уже решалась в 2015 году, но была отклонена разработчиками формата clang: https://reviews.llvm.org/D14484

Как бы то ни было, я внес простое изменение в формат clang, которое должно дать вам ваше предполагаемое поведение: https://github.com/Nikolai-Hlubek/clang/tree/ConstructorInitializer_AlwaysBreakAfterColon

Я сделал push-запрос в апстрим, но сомневаюсь, что он будет принят.

person Nikolai    schedule 03.01.2020
comment
Спасибо, скоро проверю. - person ivan.ukr; 03.01.2020
comment
Для удобства я сделал выпуск с двоичным кодом для Ubuntu16.04, поэтому вам не нужно создавать clang для его тестирования. - person Nikolai; 07.01.2020

Я лично использую

BreakConstructorInitializers: BeforeComma

но доступны и другие варианты. См. Параметры стиля формата Clang в разделе BreakConstructorInitializers. Похоже, ваш стиль будет AfterColon.

person Thomas    schedule 28.06.2019
comment
Уже есть, но на ситуацию это не влияет. Посмотрите мое обновление. - person ivan.ukr; 30.06.2019
comment
все, что я могу сказать, если я удалю эту строку из моего .clang-формата, инициализаторы больше не будут в отдельной строке каждый. может вы редактируете не тот файл? только что случилось со мной, когда я пробовал это ... - person Thomas; 30.06.2019
comment
Если вам интересно, я добавил содержимое моего .clang-формата. - person ivan.ukr; 01.07.2019
comment
Ваш файл работает нормально после того, как я удалил ConstructorInitializerAllOnOneLineOrOnePerLine: 'false' - person Thomas; 01.07.2019
comment
попытался удалить - дает мне A (): m_a (someValue1), m_b (someValue2), m_c (someValue3) как одну строку, и я хочу, чтобы эти m_a, m_b и m_c были на отдельных строках ... - person ivan.ukr; 01.07.2019
comment
Может баг в clang-формате? По здравому смыслу ConstructorInitializerAllOnOneLineOrOnePerLine: «false» должно было поместить их в отдельные строки. - person ivan.ukr; 01.07.2019

Я пытаюсь сделать то же самое. Лучшее, что я мог сделать, это:

SpaceBeforeCtorInitializerColon: true
ConstructorInitializerIndentWidth: 4
BreakBeforeInheritanceComma: false
BreakInheritanceList: AfterColon
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: AfterColon
ConstructorInitializerAllOnOneLineOrOnePerLine: true

Тем не менее, это все равно поместит список в одну строку , если вы не нарушите ограничение столбца.

person gregpaton08    schedule 08.10.2019

Есть 2 других обходных пути (с недостатками):

  • Используйте пары // clang-format off и // clang-format on вокруг списка инициализаторов -> Недостаток: clang-format также не применяет полезное переформатирование для этой части.
  • Установите ColumnLimit на 0. Это как-то исправляет использование AfterColon, заставляя его работать. Недостаток: вы не можете установить ограничения на столбцы для своего проекта. В одном из наших проектов (LMMS) мы решили предложить только ограничение на столбцы: наши соглашения о кодировании теперь содержат предложение, говорящее: «Каждая строка текста ДОЛЖНА быть длиной не более 120 символов».
  • Используйте BreakConstructorInitializers: BeforeComma. Он выглядит немного по-другому, но работает, и все инициализации помещаются в отдельную строку.
person Johannes    schedule 23.05.2020