.. docs/source/developer/cpp_code_style.rst
.. Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
.
This file is part of CamCOPS.
.
CamCOPS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
CamCOPS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with CamCOPS. If not, see .
C++ code style used
===================
.. code-block:: cpp
/*
Copyright/license boilerplate
*/
// In header (.h) files:
#pragma once
#define ANY_MASTER_SWITCHES_FOR_FILE
#define DEBUG_A_SWITCH_THAT_SHOULD_BE_OFF_FOR_RELEASE_MODE
// In source (.cpp) files:
#include "myheader.h"
// Then:
#include
#include
#include
#include
#include "myproject/libraries/in"
#include "zz_alphabetical/order"
#ifdef SOME_MASTER_SWITCH
#include "conditional/include.h"
#endif
#define SOME_MACRO(x) x; // but... really?
const QString SOME_CONSTANT;
namespace mynamespace {
// ... lower case so it's easy to distinguish Class::member from
// namespace::member
// namespace contents NOT indented
} // namespace mynamespace
class SomeClass {
// Descriptive comments
Q_OBJECT // if applicable
public:
// other classes and structs
public:
SomeClass();
// other constructors
~SomeClass();
void someFunction();
int& rFunctionReturningReference();
// ...
protected:
// functions
private:
// functions
public:
int public_member; // e.g. for structs; no "m_"
private:
int m_member_variable; // perfectly clear
static int s_static_variable;
// NOT: int mMemberVariable; // just because Stroustrup and Python habits
// NOT: int memberVariable; // helpful to have some indicator of membership
// NOT: int member_; // I hate this.
char* m_pointedto; // space AFTER the *; see Stroustrup
char* m_p_pointedto; // alternative notation; "_p_" for pointer
// ... not usually necessary.
};
// ============================================================================
// Big divider
// ============================================================================
void SomeClass::someFunction(int param)
{
// Indents are 4 spaces.
int stack_variable;
if (param > 1) {
braceEvenForSingleStatement();
}
if (very_long_condition_1 && very_long_condition_2 &&
very_long_condition_3 && very_long_condition_4) {
// we indent the subsequent parts of the "if" statement once more.
}
auto someLambdaFunction = [](int param) -> void {
statements;
};
}
// ----------------------------------------------------------------------------
// Small divider
// ----------------------------------------------------------------------------
Note other popular coding standards:
**C++**
- Summary of my preferred style above:
.. code-block:: none
SomeClass, someFunction, some_variable, m_some_member_variable
char* pointer_to_char;
- C++ Super-FAQ: https://isocpp.org/wiki/faq/coding-standards
- Stroustrup, http://www.stroustrup.com/bs_faq2.html#Hungarian
.. code-block:: none
some_variable
const int* pointer; // http://www.stroustrup.com/bs_faq2.html#whitespace
some_function // from the C++ book, anyway
- Qt coding style, https://wiki.qt.io/Qt_Coding_Style
.. code-block:: none
SomeClass, someFunction, someVariable, someMemberVariable
char *pointerToChar;
- Google C++ Style Guide, https://google.github.io/styleguide/cppguide.html#Naming
.. code-block:: none
SomeClass, SomeFunction,
some_stack_variable, some_member_variable_, kSomeConstantVariable
- https://chaste.cs.ox.ac.uk/trac/raw-attachment/wiki/CodingStandardsStrategy/codingStandards.pdf
.. code-block:: none
SomeClass, SomeFunction,
some_stack_variable, mMemberVariable, mpMemberPointer, rReferenceArg,
- Boost, http://www.boost.org/development/requirements.html
.. code-block:: none
all_names_like_this
- GCC, https://gcc.gnu.org/codingconventions.html#Cxx_Names
.. code-block:: none
m_member
s_static_member
- http://www.ivanism.com/Articles/CodingStandards.html
.. code-block:: none
SomeClass
SomeNamespace
SOME_CONSTANT
SOME_MACRO(x)
someMemberFunction
SomeGlobalFunction
m_someMemberVariable
**Other languages**
- C: Linux kernel style, https://kernel.org/doc/html/latest/process/coding-style.html
.. code-block:: none
char *linux_banner;
char *some_function();
- Python, PEP8, https://www.python.org/dev/peps/pep-0008/;
use Black (https://black.readthedocs.io/) with 79 characters per line.
**Disabling compiler/linter warnings inline**
- For example, compilers disagree on when a ``default:`` label should be
included in a ``switch`` statement
(https://github.com/quinoacomputing/quinoa/issues/158).
- For the Visual C++ compiler, an example is:
.. code-block:: cpp
#ifdef _MSC_VER // Compiling under Microsoft Visual C++
#pragma warning(push)
#pragma warning(disable: 4100) // C4100: 'app': unreferenced formal parameter
#endif
// problematic code here
// ... and if we want to resume warnings for this compilation unit:
#ifdef _MSC_VER // Compiling under Microsoft Visual C++
#pragma warning(pop)
#endif
- For Qt Creator's Clang-Tidy and Clazy, use :menuselection:`Tools --> Options
--> Analyzer`, copy a starting configuration such as "Clang-Tidy and Clazy
preselected checks [built-in]", and edit it.
**Constants in Qt code**
- It should always be preferable to use initialization over assigment. However,
"initialization as assigment" is also initialization:
.. code-block:: cpp
const MyObject x(5); // initialization via MyObject::MyObject(5)
const MyObject x = 5; // also initialization via MyObject::MyObject(5)
const MyObject x = MyObject(5); // silly
MyObject x; x = 5; // assignment via MyObject::operator=(5)
We can demonstrate by inspecting the assembly output, e.g. at
https://godbolt.org/ with this code:
.. code-block:: cpp
#include
void f() {
const int a = 1;
const int b(2);
int c;
c = 4;
const std::string d("d");
const std::string e = "e"; // same output as for d
std::string f;
f = "f";
}
The C++ standard defines initialization to include these cases:
https://en.cppreference.com/w/cpp/language/initialization. However, it seems
there isn't very much difference here of day-to-day importance.
QStringLiteral() may sometimes be preferred over raw strings by the linter.
- In 2023 the linter complains about e.g.
.. code-block:: cpp
const int FIRST_Q = 1; // OK
const QVector Q_REVERSE_SCORED{8, 12}; // non-POD static (QList) [clazy-non-pod-global-static]
const QString APREFIX("a"); // non-POD static (QString) [clazy-non-pod-global-static]
See
https://github.com/KDE/clazy/blob/master/docs/checks/README-non-pod-global-static.md;
https://www.kdab.com/uncovering-32-qt-best-practices-compile-time-clazy/;
https://doc.qt.io/qt-6/qglobalstatic.html#Q_GLOBAL_STATIC. But
Q_GLOBAL_STATIC is quite ugly, and it's not clear that a real problem is
being solved. See also
https://forum.qt.io/topic/97838/static-const-qstring-implicit-sharing-issue/14;
https://forum.qt.io/topic/111693/storing-qstring-constants-without-global-static-non-pod-values.
Possibly ignoring the warnings is fine in this case.
- But then on other machine it gets past that, and instead complains like this:
.. code-block:: cpp
const QString APREFIX("a"); // QString(const char*) being called [clazy-qstring-allocations] QString(const char*) ctor being called [clazy-qt4-qstring-from-array]
const QString APREFIX(QStringLiteral("a")); // OK but long-winded