Skip to content

Coding Style Guide

jonwd7 edited this page May 26, 2017 · 19 revisions

[WIP]

Indents/Newlines

All indentation in cpp and h files should be tabs-only with a few exceptions. Spaces can be used for alignment inside of block comments, consecutive assignments, multi-line initialization lists, or multi-line argument lists.

NOTE: All examples here have been converted to spaces because of GitHub's absurd 8-space tab size default.

Control Flow

For: if, for, while, do, switch... place the opening bracket on the same line as the statement, and place any continuation statements (else, else if, while in the case of do) on the same line as the closing bracket.

// Prefer           //  // NOT
if ( x ) {          //  if ( x )
    statement;      //  {
} else if ( x ) {   //      statement;
    statement;      //  }
} else {            //  else if ( x )
    statement;      //  {
}                   //      statement;
                    //  }
// Avoid            //  else
if ( x )            //  {
    statement;      //      statement;
else if ( x )       //  }
    statement;
else
    statement;

// Do NOT mix brackets
if ( x ) {
    statement;
} else
    statement;

To improve readability for heavily nested control flow structures, you can use the alternate indent style for the one or two outermost scopes.
But note that heavy nesting is a possible sign you need to restructure the code

See Control Flow Specifics for more information.

Data Structures

For functions, methods, struct, union, class do not use the above bracket format. Give a new line for each bracket:

void doFoo()
{
    statement;
}

class Foo
{
public:
    Foo();
    ~Foo();

protected:
    struct MyStruct
    {
        int x;
        int y;
    };

private:
    void bar();
};

void Foo::bar()
{
    statement;
}

See Data Structure Specifics for more information

Control Flow Specifics

If you do use braceless, do NOT nest comments or bracketed blocks under them.

// BAD
if ( x )
    for (;;) {
        statement;
        break;
    }

// BAD
if ( x )
    // Some comments
    statement;
else
    // Some other comments
    statement;

Please consider the evils of braceless before using them:

// EVIL
if ( x )
    if ( y )
        statement;
else
    // If not y... not "if not x"
    statement;

// EVIL
if ( x )
    // statement; // Commented out intended statement

// "if x" falls through to next statement:
nextStatement;

// EVIL
if ( x )
#ifdef WIN32
    statement;      // One could insert something, not noticing
#else
    otherStatement; // ...or take out the #else not realizing the implications
#endif

As with else and else if, for do place the while statement on the same line as the closing bracket:

do {
    statement;
} while ( false );

For switch, do not indent the cases. Indent the scope brackets and the case body. Do not leave break dangling from a scope bracket... Give it a newline.

switch ( x ) {
case 1:
    {
        // Indent Scope Brackets
        statement;
    }
    break;
case 2:
    // Scopeless
    statement;
case 3:
default:
    break;
}

Data Structure Specifics

Give empty bodies their own newlines for each bracket. For constructor initializers, keep the parent class on the same line as the definition, and any other members on the next line, indented 4 spaces. If the parent classes are too long put them all on the next line, starting with the colon :. If both declared and defined in the header file, a single line is fine, but don't define implementation in the header!

// bar.cpp
Bar::Bar()
{
}

Bar::Bar( const QModelIndex& index, SomeObject* someObj ) : Foo( index ), 
    myObj( someObj ) 
{
}

// Or
Bar::Bar( const QModelIndex& index, SomeObject* someObj )
    : Foo( index ), myObj( someObj ) 
{
}

// bar.h
class Bar
{
public:
    Bar();
    // Discouraged
    Bar( const QModelIndex& index, SomeObject* someObj ) : Foo( index ), myObj( someObj ) {}
    // Define in .cpp instead
    Bar( const QModelIndex& index, SomeObject* someObj );
};

Access specs should never be indented, everything else should, including Qt macros.

class Bar
{
    Q_OBJECT
public:
    Bar();

protected:
    SomeObject* myObj;
};

Comments

For if/else chains, do not put comments for the scope on the same line as the opening bracket. For single-line if statements, if you need to leave a comment, do so after the semi-colon.

// Good                          // Bad
if ( true ) {                    //  if ( true ) { // This is true
    // This is true              //      statement;
    statement;                   //  } else { // It is not true
} else {                         //      statement;
    // It is not true            //  }
    statement;
}

// OK                            // Very bad
if ( true )                      //  if ( true )
    statement; // This is true   //      // This is true
else                             //      statement;
    statement; // It is not true //  else
                                 //      // It is not true
                                 //      statement;

Indent/Newline Exceptions

Control Flow

Multi-line if conditionals (et al.) should have their opening bracket on a new line.

// BAD
if ( !something && somethingElse == 0
    && ( eitherThis || orThat ) ) {
    statement;
}

// GOOD
if ( !something && somethingElse == 0
    && ( eitherThis || orThat ) )
{
    statement;
}

Single-line braceless if statements can be OK in some circumstances (i.e. readability), but NEVER for return statements, and NEVER for if/else/else if chains

// OK
if ( kbd[ Qt::Key_Up ] )    doUp();
if ( kbd[ Qt::Key_Down ] )  doDn();
if ( kbd[ Qt::Key_Left ] )  doLt();
if ( kbd[ Qt::Key_Right ] ) doRt();

// NOT OK                  // INSTEAD
if ( true ) return;        if ( true )
                               return;
                           
// NOT OK                  // INSTEAD
if ( true ) return;        if ( true )
else doSomethingElse();        return;
                           else
                               doSomethingElse();

Whitespace

Spaces

There should be spaces around all of the following without exception:

  • Assignment =
  • Arithmetic + - * / %
  • Compound assignment += -= *= /= %= >>= <<= &= ^= |=
  • Comparison == != > < >= <=
  • Logical OR ||
  • Logical AND &&
  • Bitwise & | ^ << >> (minus Bitwise NOT)
  • Ternary conditional ? :

Grouping parentheses () should generally have no inner padding, outermost group padding and collapsing of adjacent grouping operators:

  • Good: if ( ((A || B) && C) || D )
  • Bad: if ( ( ( A || B ) && C ) || D )
  • Very Bad: if (( (A || B ) && C )||D)

The following should be "spaceless" in that they don't contribute to padding, nor do they collapse padding (i.e. when against the list of operators that should have padding):

  • Logical NOT !
    • if ( !isTrue() )
    • NOT if ( ! isTrue() )
    • isFalse = !isTrue();
    • NOT isFalse = ! isTrue();
  • Bitwise NOT ~
  • Increment ++
  • Decrement --
  • Dereference *a (object pointed to by a)
  • Address-of &a (address of a)

These should collapse all whitespace against adjacent objects:

  • Type cast (C style) ()
    • foo = (const char *)bar;
    • NOT foo = ( const char * ) bar
    • Note: The complete lack of padding helps it to be more immediately identified as a cast.
  • Array subscript []
    • myArray[0];
    • NOT myArray [ 0 ];
  • Scope resolution :: Foo::Foo()
  • Element by pointer -> myObject->element
  • Element by reference . myObject.element

Newlines

Generally, give a blank new line above the following*:

  • return statements
  • if, for, do, while, switch statements
  • Access spec blocks (public, protected, private, etc.)

Generally, give a blank new line below the following*:

  • Last bracket in an if or if/else block.
  • for, do, while, switch blocks.

*: Do not pad with a blank line if there is an opening or closing bracket. Though generally give a final return statement in a scope a newline above it

Alignment

Consecutive assignments

If assigning to multiple consecutive variables, you may align the = with spaces if it makes the block of assignments more legible.

Enums

If initializing any enumerators with values, align consecutive = within reason. However, always attempt to align any trailing comments for each enumerator.

Multi-line Expressions and Lists

Attempt to align consecutive lines vertically to the inside of the initial ( or { or =. For strings of && or || do not leave the operator trailing on the previous line but instead start the newline with the operator.