Skip to content

The (Tentative WIP) XPTools CPP Style Guide

tngreene edited this page Apr 12, 2017 · 4 revisions

The (Tentative WIP) XPTools CPP Style Guide

XPTools is (as of writing) at least 11 years old, and has been primarily written by one author (bsupnik.) As such there are multiple coding styles used throughout the code base. Going forward we want to develop a uniform style guide to follow and adopt a static code analysis formatter to enforce it. Until then, here is a tentative style guide for new code. Be locally consistent above using new rules. (Note: Some of the content of this guide is take from Google's C++ style guide, however there are changes to be aware of!)

Data Types

bool vs int

Under the "say what you mean principle", use the bool datatype for values that will be true or false and int for numeric values.

Given WED's lack of code documentation, returning a boolean over a 0 or 1 is more clear. It also discourages the use of returning hard coded and brittle (and likely undocumented) error codes instead of using an enum or other safer constructs.

C++ vs C-Style strings

Going forward, always use C++ strings instead of C-Style const char* strings. Update the existing APIs as is convenient.

The only exception is for creating debug labels. For example:

void make_a_widget_for_fred(int foo, xflt bar, const char * debug_label);

Commenting

// vs /**/

Prefer C++ style comments (//) over C style comments (/**/) as C style comments don't nest. Use #if 0 ... #endif for disabling large chunks of code.

Documentation

Place variable and method documentation comments on the line directly above their deceleration

Place the comments describing the purpose of the variable or function above the deceleration of it. This supports most IDE's ability to take this line and show it in tool tips in addition to saving horizontal space.

//Pointer to the original WED_TaxiRoute in WED's data model
WED_TaxiRoute* taxiroute_ptr;

Formatting

Conditional and Iteration Statement Brace Style

Do not use brace-less if's, else's, for's, while's unless it makes the code exceptionally beautiful and elegant. This is a bug prevention decision.

Good

if(x == 1)
{
   DoThing();
}

Bad

if(x == 1)
   DoThing();

Single line statements such as

if(x == 1) Func();

are absolutely prohibited due to the difficulty of placing a breakpoint on the expression following the selection or iteration statement.

Function Declarations and Definitions

Return type on the same line as function name, parameters on the same line if they fit. Wrap parameter lists which do not fit on a single line.

Functions look like this:

ReturnType ClassName::FunctionName(Type par_name1, Type par_name2)
{
  DoSomething();
  ...
}

If you have too much text to fit on one line:

ReturnType ClassName::ReallyLongFunctionName(Type par_name1, Type par_name2,
                                             Type par_name3)
{
    DoSomething();
    ...
}

or if you cannot fit even the first parameter:

ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
    Type par_name1,  // 1 indent
    Type par_name2,
    Type par_name3)
{
    DoSomething();  // 1 indent
   ...
}

Some points to note:

  • Choose good parameter names.
  • Parameter names may never be omitted.
  • If you cannot fit the return type and the function name on a single line, break between them.
  • If you break after the return type of a function declaration or definition, do not indent.
  • The open parenthesis is always on the same line as the function name.
  • There is never a space between the function name and the open parenthesis.
  • If first parameter's type is on the first line, there is no space between the open parenthesis and it.
  • The open curly brace is always on the next line, with the exception of empty implementations of methods.
  • The close curly brace is always on the last line by itself, with the exception of empty implementations of methods.
  • All parameters should be aligned if possible.
  • Wrapped parameters have a 1 indent.

Rules for empty implementations of methods:

  • There should be a space between the close parenthesis and the open curly brace.
  • Open and closed curly braces appear on the same line with 0 or 1 spaces in between.
virtual	void DragScroll	(int x, int y) { }

Line Endings

Use Unix line endings only.

Line Length

Aim for 80 characters, 100 is okay too, stop at 120.

Non-ASCII Characters

All identifiers must be in ASCII. Hard coded strings and characters featuring Unicode characters in code should be written with the C++ Unicode literal escape sequence and given a comment with the actual Unicode character and a description of it.

Good

//â, latin small letter a with circumflex
string facade_type = "ch\u00E2teauesque";

Bad

//â, latin small letter a with circumflex
string façade_type = "châteauesque";

We can afford Unicode in comments to be trashed by an encoding change, not in source code.

Spaces vs. Tabs

Use tabs to indent, spaces inside the rest of the line, even for spans of greater than 4 spaces.

Headers

The #define Guard

Header guards should be in the form of FILE_NAME_IN_ALL_CAPS_H. For example GUI_PopupButton.h's guard is GUI_POPUPBUTTON_H. All caps, no extra spaces inserted between words. We do not use #pragma once.

Class Declarations

Declaration Order

Put the public interface portion first, followed by protected members, and finally private members. Within each order, group by related purpose and order alphabetically. Use newlines and comments between sections to mark them. Inherited functions should be especially grouped together and marked, with a comment above saying which class they originate from. Omit empty sections.

Method Declarations

Default Parameters

Default parameters should go in the declaration instead of in the definition. This better communicates if there is or is not defaults set and the expected behavior of the method without having to look at the definition.