Source Code Style Guide

class

Use the following order for access specifiers. List constructors first followed by destructors. Methods should appear before data members.

class QWidget : public QObject
{
CS_OBJECT(QWidget)
enum Categories {
ItemA,
ItemB,
}
public:
// constructors
// destructors
int chop();
protected:
// omit specifier if there are no declarations
private:
someDataType m_data;
friend bool operator==(const QWidget &widget1, const QWidget &widget2);
};

(clang format) Brace wrapping, AfterClass: true

struct or enum

For a struct or enum leave the curly on the declaration line.

struct {
int m_count;
};

(clang format) Brace wrapping, AfterStruct: false

namespace

Do not indent the code inside a namespace.

namespace SomeName {
int doThis()
{
. . .
}
} // namespace SomeName
constructors and destructors

Constructors, destructors, or anything with an initializer list.

Ginger(int data)
: Parent()
{
}
OR
Ginger(int data)
: Parent()
{ }

(clang format) SplitEmptyFunction: true

inline methods
data_type count() const {
return m_data.size();
}

(clang format) AfterFunction: false

out-of-line methods
data_type QWidget::count() const
{
return m_data.size();
}
templates

Declarations and the implementation should have the template parameters on the first line and the function or method name on the next line.

template<typename T>
bool convert(float amount)
constructs

if, else, for, while

Use curly braces even when there is only one line of code in the block. Prefer the "true" block as the first branch of an if.

increment and decrement

Use pre-increment and pre-decrement unless the code only works with a post increment/decrement.

typedef

A using declaration is preferred instead of a typedef.

// older syntax
typedef QList<QWaitConditionEvent *> EventQueue;
// preferred
using EventQueue = QList<QWaitConditionEvent *>;
switch

Add a default or ensure every case is listed.

Use the fallthrough attribute to indicate the code really should proceed to the next case. This will avoid a compiler warning.

switch (currentState) {
case FtpState::Begin:
break;
case FtpState::Success:
currentState = FtpState::Idle;
[[fallthrough]];
case FtpState::Idle:
startNextCommand();
break;
case FtpState::Waiting:
break;
default:
break;
}

(clang format) IndentCaseLabels: true

unused parameter

If a parameter is not used you can remove the name in the parameter list in the cpp file. Do not remove the name in the class declaration located in a public header because it may be used in the API documentation.

bool QFontDatabase::isFixedPitch(const QString &family, const QString &) const
{
. . .
}

If the variable is used in a branch of an #ifdef use the following code to remove a compiler warning.

bool QFontDatabase::isFixedPitch(const QString &family, const QString &style) const
{
(void) style;
}

(clang format) SpaceAfterCStyleCast: true

pointer and reference alignment

Put a space before a star or ampersand and no space after it.

QList<int *> list;
const DataType &value;
void append(QList<T> &&other);
void someMethod(const QString &str);
horizontal spacing

Three spaces. Do not use tabs.

Add exactly one space to the left and right for all binary operators.

If a line of code is more than about 100 to 120 characters, wrap the line and indent six spaces.

bool QDateTimeParser::potentialValue(const QString &str, int min, int max, int index,
const QDateTime &currentValue, int insert) const
{
. . .
}
vertical spacing

Place a blank line at the start of a long or difficult to read block.

(clang format) KeepEmptyLinesAtTheStartOfBlocks: true

align bit fields

Adjust horizontal spacing in bit field declarations.

(clang format) AlignConsecutiveBitFields: true

semicolon

Required at the end of a class, enum, or struct.

Do not use a semicolon at the closing of a namespace.

variable names

Variable names should have a semantic meaning and not be excessively long. Avoid using single letters or names like li or x. For class member variables use "m_" before the rest of the variable name.

Use iter, iter_begin, or iter_end instead of variable names like it.

The variable name "item" should be used in a "range based for" when looping over a container.

for (const auto &item : some_container)

It is acceptable to use j or k inside a for loop if the variable meaning is a loop counter and the code is short.

return variable name

For the return variable name use retval. This is a variable name which should not be used for any other meaning to avoid conflicts.

int retval = 42;
...
return retval;
parameter names

For copy and move constructors, assignment operators, and swap, use the parameter name other.

MyClass(const MyClass &other);
MyClass& operator=(const MyClass &other);
variable casing

Variable names should always start with a lower case letter. If the name contains more than one word, all words after the first word should start with a capital letter.

An exception is for conformance with the STL for names like size_type and const_iterator.

Class names should always start with a capital letter.

digraphs and trigraphs

Digraphs and trigraphs are sequences of two and three characters in source code which are meant to be treated as if they were single characters. Trigraphs were removed in C++17 and are no longer supported.

Use the operators and not the text alternative.

Operator (correct) Alternative (avoid)
&& and
&= and_eq
& bitand
| bitor
~ compl
! not
!= not_eq
|| or
|= or_eq
^ xor
^= xor_eq
{ <%
} %>
[ <:
] :>
# %:
## %:%:
range based for

Whenever possible use a range based for.

Use auto or const auto for the data type when it will improve readability.

catch unit tests

▸ Include Files

Include CopperSpice headers followed by the header <catch2/catch.hpp>.

▸ Macros

Use REQUIRE(x) instead of CHECK(x).

▸ Variable Names

The variable being tested should be named data for consistency. If multiple variables are required use data1, data2, and so on.

▸ Code

Place any required support code such as a class or a struct before all unit tests.

▸ Ordering

For any given class, type trait tests should come first followed by constructor tests. Remaining test cases should be in alphabetical order, unless there is a related group which makes more sense to test together.

▸ Test Case Names

The names of test cases should consist of the name of the class in mixed case, followed by the subject of the test in all lowercase. If the subject contains multiple words, separate those words by underscores. Do not use any non-letter symbols in the name of the test. If there are multiple tests for the same subject, use a suffix of _a, _b, and so on.

The unit test name for the assignment operator should be assign. The name for all other operators should be operator_a, operator_b, and so on.