-
Notifications
You must be signed in to change notification settings - Fork 1
Coding Guidelines
Library code should be placed in namespaces. Also, all files should be prefixed with a corresponding file name prefix. For example:
Library/Module | Class Name Example | Namespace | Header file | Implementation file | Header Include Guard |
---|---|---|---|---|---|
IBK (regular classes) | ArgParser | IBK | IBK_ArgParser.h | IBK_ArgParser.cpp | IBK_ArgParserH |
IBK (templates) | matrix_view<> | IBK | IBK_matrix_view.h | IBK_matrix_view.cpp | IBK_matrix_viewH |
IBK | bitfield | IBK | IBK_bitfield.h | IBK_bitfield.cpp | IBK_bitfieldH |
AN: The _ notation for templates is used to have similar appearance as templates from the C++ standard library, for example,
std::back_inserter()
.
Generally, a clean and concise coding style should be used, for example, place your opening and closing braces like in the following example:
// Short function declarations may have the opening brace in the same line
void someFunction(int t) {
// indent with one tab character
for (int i=0; i<t; ++i) { // also place the opening brace in this line
// code
}
// longer for-clauses with more than one line should place
// the opening brace into the next line to mark the opening scope.
for (std::vector<double>::iterator it = m_localVec.begin();
it != m_localVec.end(); ++it)
{
// code
}
// similar rules apply for if and other clauses, for example
if (value == 15 || takeNextStep ||
(firstStepCounter > 15 && repeat))
{
// code
}
}
// Longer function declarations in two or more lines should place
// the opening brace in the next line to clearly mark the start of the scope.
void someFunctionWithManyArguments(const std::vector<double> & vec1,
const std::vector<double> & vec2,
const std::vector<double> & vec3)
{
// code
}
// The following source code shows typical indentation rules
void indentationAndOtherRules() {
// recommendation: use 'if (' instead of 'if( '
if (someCondition) {
// code
}
// put else in a separate line and put code comments
// like this before the else clause to document what's
// done in the else block
else {
//
}
// put spaces between ; separated tokens in for loops
for (i=0; i<20; ++i) {
}
// indent switch clauses like the example below
switch (condition) {
case WELL:
// code
// more code
break; // break on same level as case
// document case clauses before the case
case SICK:
// code
return "sick";
// when you declare local variables within switch
// open a dedicated scope
case DONT_KNOW: {
int var1; // local variable, only valid for case clause
// code
}
break;
// if you have many short case clauses, you can use properly indented one-line versions
case ABIT_SICK : return "a bit sick";
case ALITTLEBIT_SICK : return "a little bit sick";
case QUITE_WELL : break;
default: ; // always implement the default clause, even if
// not possible to avoid compiler warnings
} // switch (condition)
// in long nested scopes, document the end of the scope as done in the line above
// another example of documented nested scopes
for (k=0; k<10; ++k) {
for (j=k; j<10; ++j) {
// lots of code
} // for (j=k; j<10; ++j)
} // for (k=0; k<10; ++k)
}
- Indentation is done with tabs, editors set to 4 spaces per tab, set your IDE/Editor accordingly.
- Doxygen comments are to be used, in the format
{{{/*! */}}}
- Doxygen Documentation should be placed exclusively in header files for all functions and variables, in implementation files only standard C/C++ comments should be used
- Examples should be provided with typical operations (using code/endcode tags).
- Header files get the .h extension, Implementation files get .cpp (or .c for plain c-code).
- Source code files (headers and cpp files) are prefixed, for example
IBK_
, with the following naming conventions:
ClassName
IBK_ClassName.h
IBK_ClassName.cpp
-
Include guards for header files are written exactly as the header file name, but with the
.h
substituted with anH
IBK_ClassNameH
-
Class declaration access levels are to be ordered: public, protected, private
-
All source code is to be wrapped in the namespace IBK
Example:
namespace IBK {
// code
} // namespace IBK
- Member variables are prefixed with
m_
to distinguish them from local variables/function arguments.
Example:
// m_ style
m_myMemberVariable;
- Typenames should be camel-cased by default, this holds for: enums, structs, template typenames
- global function use
_
notation to distinguish them from member or local functions
Example:
// names of global functions are composed of lower case words connected with underscores
std::string format_time_difference(double delta_t);
// descriptive names are to be used
void break_string(const std::string& msg, std::vector<std::string>& lines, int line_width);
- in the naming convention for classes we distinguish between template and normal classes:
Regular classes are given Camel-cased-names. Apart from that, the rules for template classes apply as well. Consider the following code example as guide for valid naming conventions.
/*! Every class should be documented, at least briefly.
It is useful to include some code examples using doxygen source code
snippets on how to use the function. This allows users to copy source code snippeds from
the documentation. For example:
\code
// instatiate the class
MyTestClass c;
// set the property
c.setFirstNumber(15);
// check if the number is valid
if (c.isValid()) {
// code
}
\endcode
*/
class MyTestClass {
public:
/*! Doxygen comments are used for documenting functions. */
MyTestClass();
/*! A typical function declaration starts lower case and continues
in camel-case
\param n Function arguments are documented individually,
unless they are trivial.
\return Return values are documented when meaning is not
clear from function description.
*/
bool readTestClassList(int n);
/*! Getter functions for property-like variables get the name of the
variable without the m_
The declaration for the getter function should always
be declared as 'const'.
*/
double firstNumber() const;
/*! The matching setter function is prefixed with 'set' followed by
the capitalized property name. */
void setFirstNumber(double val);
/*! Getter-Functions for boolean state variables are prefixed with 'is'. */
bool isValid() const;
/*! Setter-Functions for boolean state variables are prefixed as usual with 'set'. */
void setValid(bool valid);
/*! Publicly accessible variables do not get any prefixes or suffixes. */
double maxValue;
private:
/*! Private member variables that have getter and setter functions
are named just as the getter function, but prefixed with a 'm_'.
*/
double m_firstNumber;
/*! Member variable corresponding to isValid() and setValid().
\see isValid()
\see setValid()
*/
bool m_valid;
};
The using namespace xxx
statement must not be used in header files at all.
In general, namespace prefixes should be included in the code to identify the origin of a symbol/function. The key motivation for this is to help readers of the code to find out which library a functio/class belongs too. Even if it looks a bit verbose, as in the following example, still include the namespace.
std::cout << std::fixed << std::setprecision(4) << std::setwidth(10) << std::right << value << std::endl;