Articles

C++ style guide

In howto on Aug 29, 2013 by theoryl Tagged: , , ,

I have always wished that my codes are more readable. So I decided to adopt a proper style guide for my codes. I decided to follow the style guide from Google and the documentation guide from Doxygen with Markdown text formatting.

My boilerplate:

/** 
 *  @file Example.h
 *  @brief This is an example code
 *  @author user <user@example.com>
 *  
 *  A looong description.
 *  A formula: \f$ \sqrt{ a^2 + b^2 } \f$
 */

#ifndef EXAMPLE_H_
#define EXAMPLE_H_

#include <vector>  //  ordered by C library, C++ library, other libraries' .h, user's .h

...

#endif  // EXAMPLE_H_

(Indent with 4 spaces, although Google recommends 2 spaces. No tabs.)

My class template:

/** 
 *  @class Test
 *  
 *  Some description.
 */
class Test {
  public:
    /** An enum type. 
     *  Some description.
     */
    enum EnumType {
        int EVal1,   ///< enum value 1
        int EVal2    ///< enum value 2
    };

    /// Default constructor
    Test();
    /// Constructor
    Test(int value)
          : value_(value);
    /// Destructor
    ~Test() {}

    void member();   ///< a member function
    
  private:
    int value_;      ///< an integer value
};

class ChildTest : public Test {
  private:
    int child_value_;
};

(Comment block must be placed in front of the class. Declare in order typedefs and enums, static consts, constructors, destructor, methods, class members.)

My function template:

/** 
 *  This function takes two arguments and returns an integer value.
 *
 *  @param a An integer argument
 *  @param b A const char* argument
 *  @return  A result
 */
int TestFunction(int a,const char *s) {
    if (condition) {  // No spaces inside parentheses
        ...
    } else {  // The else goes on the same line as the closing brace.
        ...
    }
    for (int i = 0; i < kSomeNumber; ++i) {
        ...
    }
    ...
}

ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
        Type par_name1,  // 8 space indent
        Type par_name2,
        Type par_name3) {
    DoSomething();  // 4 space indent
    ...
}

(Comment block must be placed in front of the function. Input arguments are values or const references while output arguments are pointers. Prefer small and focused functions)

Some common special commands:

/**
 *  @file to document a file.
 *  @namespace to document a namespace
 *  @struct to document a C-struct.
 *  @var to document a variable or typedef or enum value.
 *  @def to document a #define.
 *  
 *  @bug bug description
 *  @todo paragraph describing what is to be done
 */

Horizontal rule

//______________________________________________________________________________

Below are a few examples I referenced from. Example directly from Doxygen:

/**
 *  A test class. A more elaborate class description.
 */
class Test
{
  public:
    /** 
     * An enum.
     * More detailed enum description.
     */
    enum TEnum { 
          TVal1, /**< enum value TVal1. */  
          TVal2, /**< enum value TVal2. */  
          TVal3  /**< enum value TVal3. */  
         } 
       *enumPtr, /**< enum pointer. Details. */
       enumVar;  /**< enum variable. Details. */
       
      /**
       * A constructor.
       * A more elaborate description of the constructor.
       */
      Test();
      /**
       * A destructor.
       * A more elaborate description of the destructor.
       */
     ~Test();
    
      /**
       * a normal member taking two arguments and returning an integer value.
       * @param a an integer argument.
       * @param s a constant character pointer.
       * @see Test()
       * @see ~Test()
       * @see testMeToo()
       * @see publicVar()
       * @return The test results
       */
       int testMe(int a,const char *s);
       
      /**
       * A pure virtual member.
       * @see testMe()
       * @param c1 the first argument.
       * @param c2 the second argument.
       */
       virtual void testMeToo(char c1,char c2) = 0;
   
      /** 
       * a public variable.
       * Details.
       */
       int publicVar;
       
      /**
       * a function variable.
       * Details.
       */
       int (*handler)(int a,int b);
};

Example from Wikipedia Doxygen article:

/**
 * @file
 * @author  John Doe <jdoe@example.com>
 * @version 1.0
 *
 * @section LICENSE
 *
 * This program 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 2 of
 * the License, or (at your option) any later version.
 *
 * This program 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 at
 * http://www.gnu.org/copyleft/gpl.html
 *
 * @section DESCRIPTION
 *
 * The time class represents a moment of time.
 */
 
class Time {
 
    public:
 
       /**
        * Constructor that sets the time to a given value.
        *
        * @param timemillis Number of milliseconds
        *        passed since Jan 1, 1970.
        */
       Time (int timemillis) {
           // the code
       }
 
       /**
        * Get the current time.
        *
        * @return A time object set to the current time.
        */
       static Time now () {
           // the code
       }
};

Example from screen3d:

#ifndef SAMPLE_H_
#define SAMPLE_H_

/**
 * \file Sample.h
 * \brief sample class for Doxygen comments
 * \author user
 *
 * This class is used to present some of the Doxygen ways to do comments for Screen 
 * (this is a long description). 
 */
#include <string>
#include <list>

/**
 * namspace for Doxygen presentation
 */
namespace doxygen{
  /**
   * \brief brief class description
   * \bug this class doesn't do anything
   *
   *  Long class description
   */
  class Sample{
  private:
    std::list<std::string> _list; ///< a list
    std::list<std::string>::iterator _listIt; ///< iterator on list
                                                

  public:
    /**
     *  \brief constructor
     *
     *  Sample class constructor
     *
     *  \param[in] list a list in parameters
     */
    Sample(std::list<std::string> iList);

    /**
     *  \brief Destructor
     *
     *  Sample class destructor
     */
    virtual ~Sample();

  public:
    /**
     *  \brief add to list
     *
     *  Method that add a \e thing to the list and return \e true if added
     *
     *  \param[in] iThing thing to add
     *  \return true if added
     */
    bool add2(std::string iThing);

    /**
     * \brief add to list
     *
     * Method that add a \e thing to the list
     *
     * \param[in] iThing thing to add
     *
     * \deprecated this method is deprecated
     */
     void add(std::string iThing);

  };
} 

#endif

Example from GLAST experiment’s Science Analysis Software (SAS) recommendation:

/** @file Template.h
 * @brief Declaration of class Template
 *
 * $Header: /nfs/slac/g/glast/ground/cvs/workbook/pages/advanced_doxygen/pr_usingDoxygen.htm,v 1.1.1.1 2007/06/29 15:03:16 chuckp Exp $
 */ 
#ifndef CLASSTEMPLATE_H
#define CLASSTEMPLATE_H

// [C Headers]
extern "C" {
}

// [C++ Header files]
#include "SomeClass.h"

// [forward declarations]
class AnotherClass;

/** 
 * @class ClassTemplate
 *
 * @brief This is an example class.
 *
 * This comment block is @e required for all class declarations.
 * Please remove comments that are bracketed by [..]. These comments are there 
 * to provide instructions to developers while writing their code. 
 * Obvious member variables and functions, such as get and set routines and 
 * default constructors and destructors, should not be documented as this 
 * clutters the files. Use standard C++ comments for those comments you wish 
 * Doxygen to ignore. If the class has many members - you may consider 
 * providing separate public, protected, private sections for member functions
 * and member variables to improve readability. In addition it may be useful to
 * form member groups preceded by a header as shown below.
 *
 * Please note that the \$Header\$ keyword specified below is a RCS keyword, 
 * and will inflate into the version, name, etc for this file.
 * 
 * @author Some Body
 * 
 * $Header $
 */

class ClassTemplate {

public:
ClassTemplate();
~ClassTemplate();

int getIntMember() { return m_intMember; };
void setIntMember(const int i) { m_intMember = i; };

/**
 * Provide detailed desciption of this function
 * @param parmeter1 Describe this parameter

 * Here is an example of inserting a mathematical formula into the text:
 * The distance is computed as /f$\sqrt{ (x_2-x_1)^2 + (y_2 - y_1)^2 }/f$
 * If we wanted to insert the formula centered on a separate line:
 * /f[
 * \sqrt{ (x_2-x_1)^2 + (y_2 - y_1)^2 }
 * /f]
 * Please note that all formulas must be valid LaTeX math-mode commands. 
 * Additionally, to be processed by Doxygen, the machine used must have 
 * LaTeX installed. Please see the Doxygen manual for more information 
 * about installing LaTeX locally.
 */
void publicMemberFunction(int parameter1);

/**
 * Provide a detailed description of this function.
 * @return Describe the return values.
 */
bool anotherPublcMemberFunction();

static int getStaticIntMember() { return s_staticIntMember; };

/** @name Header for Group1
 * [ Description of Group1 ]
 */
//@{
// [ members of Group1]
bool yetAnotherFunction1();
int yetAnotherFunction2();
//@}

private:

/// Provide a description of this class member 
/// [note that the m_ prefix is not used for static members]
static int s_staticIntMember;
/// Provide a description of this class member
int m_intMember;
/// Provide a description of this class member
float m_floatMember;

}

#endif // CLASSTEMPLATE_H 

/** @file Template.cxx
 * @brief Definition of class Template
 *
 * $Header: /nfs/slac/g/glast/ground/cvs/workbook/pages/advanced_doxygen/pr_usingDoxygen.htm,v 1.1.1.1 2007/06/29 15:03:16 chuckp Exp $
 */ 
// File and Version Information:
// $Header: /nfs/slac/g/glast/ground/cvs/workbook/pages/advanced_doxygen/pr_usingDoxygen.htm,v 1.1.1.1 2007/06/29 15:03:16 chuckp Exp $
//
// Description:
// ClassTemplate provides an example of code documentation for the 
// implementation of a class. These comments will not be processed by
// Doxygen - but are here for developers to identify this source file.
//
// Note that those sections of the method comment headers that are unused,
// may be omitted
//
// Author(s):
// Author1 
// Author2 

#include "PackageName/ClassTemplate.h"

int ClassTemplate::s_staticIntMember;

ClassTemplate::ClassTemplate() {
}

ClassTemplate::~ClassTemplate() {
}

void ClassTemplate::publicMemberFunction(int parameter1) {
// Purpose and Method: This routine is an example public member function.
// Inputs: parameter1 is an example input parameter
// Outputs: None
// TDS Inputs: None
// TDS Outputs: None
// Dependencies: None
// Restrictions and Caveats: None

// [Code inside function should be documented using standard C++ comments]
}

bool ClassTemplate::anotherPublicMemberFunction() {
// Purpose and Method: This routine is an example execute routine for a 
// Gaudi algorithm.
// Inputs: None
// Outputs: A bool, where true denotes something and false denotes 
// something else.
// TDS Inputs: None
// TDS Outputs: None
// Dependencies: None
// Restrictions and Caveats: None

// [Code inside function should be documented using standard C++ comments]
}

Naming conventions from Google:

  • Filenames should be all lowercase with underscores.
  • Typenames should be MixedCase without underscores.
  • Variables should be all lowercase with underscores. Member variables should end with an underscore. Global variables should start with “g”. Constants should be “k”. Configurables use mixedCase with first letter not capitalized.
  • Regular functions should be MixedCase. Accessors and mutators should be lowercase with underscores matching the name of the variable they are getting or setting.
  • Macros should be all CAPITALS with underscores. (Macros are discouraged from use.)

Whitespace conventions from Google:

  • No space before open parentheses/angles. No spaces inside parentheses/angles. Always a space before open braces.
  • Don’t use blank lines when you don’t have to. In particular, don’t put more than one or two blank lines between functions, resist starting functions with a blank line, don’t end functions with a blank line, and be discriminating with your use of blank lines inside functions.

    The basic principle is: The more code that fits on one screen, the easier it is to follow and understand the control flow of the program.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: