Menu

Coding-Guidelines

Andreas Nicolai

Coding Guidelines

File and Namespace Naming Conventions

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().

General Conventions

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)
}

Common Rules

  • Indentation is done with tabs, editors set to 4 spaces per tab, see also Qt Creator Editor Settings
  • 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
  • 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 an H

    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 and Structs

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;
};

Namespace Prefixes

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;

Related

Wiki: Qt Creator Editor Settings

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.