Skip to content

coding style guideline

Fabien Spindler edited this page Jun 27, 2024 · 18 revisions

ViSP coding style guideline

Files

  • Each class has its own header and implementation file
  • A template class has only a header file
  • The file name should match the class name
  • C++ interface headers have .h extension
  • Implementation files have .cpp extension
  • As an example, if the class is named vpMyNewClass, the header file name should be vpMyNewClass.h and the implementation file vpMyNewClass.cpp

File structure

Every source file starts with GPL-v2 license. Use existing code to get the template.

Other rules for both header and implementation files include:

  • Code lines should not be very long. Normally, they should be limited to 120 characters.
  • No tabulation should be used. Set your editor to use spaces instead. We recommend to use the provided Visual Code settings.
  • Only English text is allowed. Do not put comments or string literals in other languages.
  • Indentation is 2 spaces.
  • Each file (.h or .cpp) should end with an empty line to avoid a compiler warning
  • Each header should include visp3/core/vpConfig.h before other ViSP headers.
  • Header files must use guarding macros, protecting the files from repeated inclusion:
    #ifndef VP_MY_NEW_CLASS_H
    #define VP_MY_NEW_CLASS_H
    
    #include <visp3/core/vpConfig.h>
    ...
    #endif
    
  • C++ macro should be upper-case like in the previous example

Naming conventions

  • Class names start with a vp prefix, then each name starts with an uppercase letter. Underscores are not allowed; ie vpMyNewClass
  • Macros and enumeration constants are written with all capital letters. Words are separated by underscore. Macro should match the regular expression: ^[A-Z][A-Z0-9_]*$
  • All external functions and classes must use VISP_EXPORT, otherwise there will be linking errors on Windows.
  • Member or static functions start with a lowercase, then next words with an uppercase; ie vpMyNewClass::myNewMethod().

Class implementation conventions

  • A class should have a default constructor, a virtual destructor and a copy operator. The header file vpMyNewClass.h should contain at least the following:
    class VISP_EXPORT vpMyNewClass
    {
    public:
      vpMyNewClass();                                       // Default constructor
      virtual ~vpMyNewClass();                              // Virtual destructor
      const vpMyNewClass& operator=(const vpMyNewClass &v); // Copy operator
      ...
    };
    

Documentation

The documentation is written in doxygen style. Use the existing documentation as example. Normally, each function/method description includes:

  • a short description
  • all the parameters explained; e.g. specify, which image types are accepted, what would be the recommended values for the parameter and how they affect the algorithm etc.
  • the full description with short use samples, references to papers, formulas, etc

In order to avoid warnings when building with Xcode for iOS, the following style should be adopted for

  • Parameter description: use doxygen \param special command to describe only one parameter:

    Compliant documentation

    /*!
     * \param x : Coordinates of a point along x-axis.
     * \param y : Coordinates of a point along y-axis.
     */
    void myClass::myMethod(double x, double y)
    

    The following is not allowed:

    /*!
     * \param x,y : Coordinates of a point.
     */
    void myClass::myMethod(double x, double y)
    
  • Putting documentation after members: use doxygen ///< special character instead of //!<

    int var; ///< Value used to... 
    

Code layout

  • Currently used in ViSP and recommended formatting style looks as follows:

    if (B <= A) {
      throw (vpException(vpException::badValue, "Bad gray levels with %d <= %A", B, A)) ;
    }
    unsigned char v;
    
    double factor = static_cast<double>(B_star - A_star)/static_cast<double>(B - A);
    const unsigned int width = I.getWidth(); 
    const unsigned int height = I.getHeight();
    for (unsigned int i=0 ; i < height; ++i) {
      for (unsigned int j=0 ; j < width; ++j) {
        v = I[i][j];
    
        if (v <= A) {
          I[i][j] = A_star;
        }
        else if (v >= B) {
          I[i][j] = B_star;
        }
        else {
          I[i][j] = static_cast<unsigned char>(A_star + (factor * (v - A)));
        }
      }
    }
    
  • Use BEGIN_VISP_NAMESPACE and END_VISP_NAMESPACE macros declared in vpConfig.h to handle visp namespace. Since ViSP 3.6.1 we introduce these macros. When CMake ENABLE_VISP_NAMESPACE option is enabled, all ViSP classes are inside visp namespace. The following example shows how to use these macros, first in the header file (vpExample.h)

    #ifndef EXAMPLE_H
    #define EXAMPLE_H
    
    #include <visp3/core/vpConfig.h>
    
    BEGIN_VISP_NAMESPACE
    
    class VISP_EXPORT vpExample
    {
    public:
      vpExample();
      ...
    };
    END_VISP_NAMESPACE
    #endif
    

    and then in the vpExample.cpp file

    #include <visp3/module/vpExample.h>
    
    BEGIN_VISP_NAMESPACE
    /*!
     * Default constructor.
     */
    vpExample::vpExample()
    {
       // do something
    }
    END_VISP_NAMESPACE
    
  • When requested, use VP_EXPLICIT macro instead of explicit C++ keyword. This macro is declared int vpConfig.h file.

    #include <visp3/core/vpConfig.h>
    
    class VISP_EXPORT vpExample
    {
      public:
      // explicit vpExample(int val); // non compliant
      VP_EXPLICIT vpExample(int val); // compliant
    }
    
  • When requested, use VP_OVERRIDE macro instead of override C++ keyword. This macro is declared int vpConfig.h file.

  • Old style cast is not allowed

    Not allowed

    double pi = 3.1415;
    int val = (int)pi; 
    

    Compliant solution using rather a more verbose C++ cast style

    double pi = 3.1415;
    int val = static_cast<int>(pi);
    
  • Identifier should be shorter or equal to 31 characters

    The following examples are not allowed:

    typedef enum { car, bus, truck } vpLargeTransportationVehiculeTypename; // 37 characters
    void computeImageProcessingOnColorImage(const vpImage<vpRGBa> &I);      // 34 characters
    

    Compliant solution using rather something like:

    typedef enum { car, bus, truck } vpLargeVehiculeType;
    void computeImageProcessing(const vpImage<vpRGBa> &I); 
    
  • Use only one statement per line

    Not allowed

    switch(val) {
      case 1:
        val += 1; break; // Not allowed
    }
    

    Compliant solution:

    switch(val) {
      case 1:
        val += 1; 
        break; 
    }
    
  • A function has at least 7 parameters

    Not allowed

    void myFunction(int val1, int val2, int val3, int val4, int val5, int val6, int val7, int val8) 
    {
      // do something
    }
    

    Compliant solution:

    struct myParameters {
      int val1;
      int val2;
      int val3;
      int val4;
      int val5;
      int val6;
      int val7;
      int val8;
    };
    
    void myFunction(const myParameters &params)
    {
      // do something
    }
    
  • The prefix increment/decrement form should be used

    Not allowed

    void myFunc(int lim)
    {
      for (int i = 0; i < lim; i++) {
        // do something
      }
    }
    

    Compliant code using rather:

    void myFunc(int lim)
    {
      for (int i = 0; i < lim; ++i) {
        // do something
      }
    }