-
Henry Weller authoredHenry Weller authored
OpenFOAM C++ Style Guide
#
Code
General
- 80 character lines max
- The normal indentation is 4 spaces per logical level.
- Use spaces for indentation, not tab characters.
- Avoid trailing whitespace.
- The body of control statements (eg,
if
,else
,while
, etc.). is always delineated with braces. A possible exception can be made in conjunction withbreak
orcontinue
as part of a control structure. - The body of
case
statements is usually delineated with braces. - Stream output
-
<<
is always four characters after the start of the stream, so that the<<
symbols align, i.e.Info<< ... os << ...
so
WarningInFunction << "Warning message"
not
WarningInFunction << "Warning message"
-
- Remove unnecessary class section headers, i.e. remove
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// Check
// Edit
// Write
if they contain nothing, even if planned for ‘future use’
- Class titles should be centred
/*---------------------------------------------------------------------------*\
Class exampleClass Declaration
\*---------------------------------------------------------------------------*/
not
/*---------------------------------------------------------------------------*\
Class exampleClass Declaration
\*---------------------------------------------------------------------------*/
The .H Header Files
- Header file spacing
- Leave two empty lines between sections (as per functions in the .C file etc.)
- Use
//- Comment
comments in header file to add descriptions to class data and functions do be included in the Doxygen documentation:- Text on the line starting with
//-
becomes the Doxygen brief description; - Text on subsequent lines becomes the Doxygen detailed description e.g.
//- A function which returns a thing // This is a detailed description of the function // which processes stuff and returns other stuff // depending on things. thing function(stuff1, stuff2);
- List entries start with
-
or-#
for numbered lists but cannot start on the line immediately below the brief description so//- Compare triFaces // Returns: // - 0: different // - +1: identical // - -1: same face, but different orientation static inline int compare(const triFace&, const triFace&);
or
//- Compare triFaces returning 0, +1 or -1 // // - 0: different // - +1: identical // - -1: same face, but different orientation static inline int compare(const triFace&, const triFace&);
not
//- Compare triFaces returning 0, +1 or -1 // - 0: different // - +1: identical // - -1: same face, but different orientation static inline int compare(const triFace&, const triFace&);
- List can be nested for example
//- Search for \em name // in the following hierarchy: // -# personal settings: // - ~/.OpenFOAM/\<VERSION\>/ // <em>for version-specific files</em> // - ~/.OpenFOAM/ // <em>for version-independent files</em> // -# site-wide settings: // - $WM_PROJECT_INST_DIR/site/\<VERSION\> // <em>for version-specific files</em> // - $WM_PROJECT_INST_DIR/site/ // <em>for version-independent files</em> // -# shipped settings: // - $WM_PROJECT_DIR/etc/ // // \return the full path name or fileName() if the name cannot be found // Optionally abort if the file cannot be found fileName findEtcFile(const fileName&, bool mandatory=false);
- For more details see the Doxygen documentation.
- Text on the line starting with
- Destructor
- When adding a comment to the destructor use
//-
and code as a normal function://- Destructor ~className();
- When adding a comment to the destructor use
- Inline functions
- Use inline functions where appropriate in a separate classNameI.H file. Avoid cluttering the header file with function bodies.
The .C Sourcs Files
- Do not open/close namespaces in a .C file
- Fully scope the function name, i.e.
Foam::returnType Foam::className::functionName()
not
namespace Foam { ... returnType className::functionName() ... }
Exception When there are multiple levels of namespace, they may be used in the .C file to avoid excessive clutter, i.e.
namespace Foam { namespace compressible { namespace RASModels { ... } // End namespace RASModels } // End namespace compressible } // End namespace Foam
- Fully scope the function name, i.e.
- Use two empty lines between functions
Coding Practice
- Passing data as arguments or return values:
- Pass bool, label, scalar and other primitive types as copy, anything larger by reference.
-
const
- Use everywhere it is applicable.
- Variable initialisation using
const className& variableName = otherClass.data();
not
const className& variableName(otherClass.data());
- Virtual functions
- If a class is virtual, make all derived classes virtual.
Conditional Statements
if (condition)
{
code;
}
OR
if
(
long condition
)
{
code;
}
not (no space between if
and (
used)
if(condition)
{
code;
}
for
and while
Loops
for (i = 0; i < maxI; i++)
{
code;
}
OR
for
(
i = 0;
i < maxI;
i++
)
{
code;
}
not this (no space between for
and (
used)
for(i = 0; i < maxI; i++)
{
code;
}
Note that when indexing through iterators, it is often slightly more
efficient to use the pre-increment form. Eg, ++iter
instead of iter++
forAll
, forAllIter
, forAllConstIter
, etc. loops
Like for
loops, but
forAll(
not
forAll (
Using the forAllIter
and forAllConstIter
macros is generally
advantageous - less typing, easier to find later. However, since
they are macros, they will fail if the iterated object contains
any commas e.g. following will FAIL!:
forAllIter(HashTable<labelPair, edge, Hash<edge>>, foo, iter)
These convenience macros are also generally avoided in other container classes and OpenFOAM primitive classes.
Splitting Over Multiple Lines
Splitting return type and function name
- Split initially after the function return type and left align
- Do not put
const
onto its own line - use a split to keep it with the function name and arguments.const Foam::longReturnTypeName& Foam::longClassName::longFunctionName const
not
const Foam::longReturnTypeName& Foam::longClassName::longFunctionName const
nor
const Foam::longReturnTypeName& Foam::longClassName::longFunctionName const
nor
const Foam::longReturnTypeName& Foam::longClassName:: longFunctionName const
- If it needs to be split again, split at the function name (leaving
behind the preceding scoping =::=s), and again, left align, i.e.
const Foam::longReturnTypeName& Foam::veryveryveryverylongClassName:: veryveryveryverylongFunctionName const
Splitting long lines at an “=”
Indent after split
variableName =
longClassName.longFunctionName(longArgument);
OR (where necessary)
variableName =
longClassName.longFunctionName
(
longArgument1,
longArgument2
);
not
variableName =
longClassName.longFunctionName(longArgument);
nor
variableName = longClassName.longFunctionName
(
longArgument1,
longArgument2
);
Maths and Logic
- Operator spacing
a + b, a - b a*b, a/b a & b, a ^ b a = b, a != b a < b, a > b, a >= b, a <= b a || b, a && b
- Splitting formulae over several lines
Split and indent as per “splitting long lines at an =” with the operator on the lower line. Align operator so that first variable, function or bracket on the next line is 4 spaces indented i.e.
variableName = a*(a + b) *exp(c/d) *(k + t);
This is sometimes more legible when surrounded by extra parentheses:
variableName = ( a*(a + b) *exp(c/d) *(k + t) );
- Splitting logical tests over several lines
outdent the operator so that the next variable to test is aligned with the four space indentation, i.e.
if ( a == true && b == c )
Documentation
General
- For readability in the comment blocks, certain tags are used that are translated by pre-filtering the file before sending it to Doxygen.
- The tags start in column 1, the contents follow on the next lines and indented by 4 spaces. The filter removes the leading 4 spaces from the following lines until the next tag that starts in column 1.
- The ‘Class’ and ‘Description’ tags are the most important ones.
- The first paragraph following the ‘Description’ will be used for the
brief description, the remaining paragraphs become the detailed
description. For example,
Class Foam::myClass Description A class for specifying the documentation style. The class is implemented as a set of recommendations that may sometimes be useful.
- The class name must be qualified by its namespace, otherwise Doxygen will think you are documenting some other class.
- If you don’t have anything to say about the class (at the moment), use
the namespace-qualified class name for the description. This aids with
finding these under-documented classes later.
Class Foam::myUnderDocumentedClass Description Foam::myUnderDocumentedClass
- Use ‘Class’ and ‘Namespace’ tags in the header files. The Description block then applies to documenting the class.
- Use ‘InClass’ and ‘InNamespace’ in the source files.
The Description block then applies to documenting the file itself.
InClass Foam::myClass Description Implements the read and writing of files.
Doxygen Special Commands
Doxygen has a large number of special commands with a \
prefix.
Since the filtering removes the leading spaces within the blocks, the Doxygen commmands can be inserted within the block without problems.
InClass Foam::myClass Description Implements the read and writing of files. An example input file: \verbatim patchName { type myPatchType; refValue 100; value uniform 1; } \endverbatim Within the implementation, a loop over all patches is done: \code forAll(patches, patchi) { ... // some operation } \endcode