Difference between revisions of "C++ style guide"

From Octave
Jump to navigation Jump to search
Line 73: Line 73:
 
# The C++ wrappers for C headers (cstdlib, cassert, etc.)
 
# The C++ wrappers for C headers (cstdlib, cassert, etc.)
 
# C++ standard library headers (iostream, list, map, etc.)
 
# C++ standard library headers (iostream, list, map, etc.)
# Other POSIX headers (sys/types.h, unistd.h, etc., no need to use {{codeline|#if defined (HAVE_FOO_H)}} if existence is guaranteed because of gnulib)
 
 
# Other library header files (glpk.h, curl.h, etc., should be protected by {{codeline|#if defined (HAVE_FOO_H)}} since they may be missing on the build system)
 
# Other library header files (glpk.h, curl.h, etc., should be protected by {{codeline|#if defined (HAVE_FOO_H)}} since they may be missing on the build system)
 
# Octave's liboctave headers
 
# Octave's liboctave headers
 
# Octave's libinterp headers
 
# Octave's libinterp headers
 +
# Octave's libgui headers
 +
 +
Other POSIX headers (sys/types.h, unistd.h, etc., should not be included directly into Octave sources.  For portability, use a wrapper function.  Anything you need is probably already available as a wrapper around a function or header provided by gnulib.  See the files in liboctave/wrappers.  This is necessary because although gnulib is great for portability, it does not generally work well with C++.
 +
 +
Similarly, Windows headers should not be included directly into Octave sources.  Wrappers that provide the needed functionality in an OS-independent way should be used instead.  This is almost always possible and there are many examples in the Octave sources.
  
 
Each grouping of header files should be alphabetized unless there is some
 
Each grouping of header files should be alphabetized unless there is some
 
specific reason to not do that.  The only case where that is true is in
 
specific reason to not do that.  The only case where that is true is in
 
{{Path|oct-parse.in.yy}} and there is a comment in the file for that one.
 
{{Path|oct-parse.in.yy}} and there is a comment in the file for that one.
 +
 +
There is a strict ordering of header files/libraries that must be followed.  There are '''no exceptions''' to these rules:
 +
 +
* The functions in liboctave/wrappers may only use headers and symbols from gnulib, standard libraries, or OS-dependent libraries.  They '''must not''' use any headers or symbols from other parts of liboctave, libinterp, or libgui.
 +
* liboctave '''must not''' use any headers or symbols from libinterp or libgui.  It must be fully functional without the interpreter or GUI.
 +
* libinterp '''must not''' use any headers or symbols from libgui.  It must be fully functional without the GUI.
 +
 +
Header files should not use any "#if defined (HAVE_FEATURE)" conditionals.  This is not quite true yet, but we are almost there.  '''No new conditionals may be added.'''
  
 
== Other C++ features ==
 
== Other C++ features ==

Revision as of 08:21, 17 August 2016

A lot of GNU Octave is written in C++. This document details the C++ style used by the GNU Octave project.

Being part of the GNU project, Octave inherits the GNU coding standards.

See also the GNU Octave Octave style guide for how to write m-files.

Formatting

Indentation

Use only spaces, and indent 2 spaces at a time.

We use spaces for indentation. Absolutely do not use tabs in your code. You should probably set your editor to emit spaces when you hit the tab key.

Line Length

Keep the length of source lines to 79 characters or less, for maximum readability in the widest range of environments. This is inherited from the GNU Coding Standards.

Namespace

All code should be in the octave namespace. This is an ongoing project. We are still moving existing classes into namespaces but all new classes should go somewhere into the "octave" namespace. There is 1 extra level for namespaces inside octave to be used with care, we don't want too many namespaces. Ask before creating a new namespace.

  • Indent namespaces as any other block. Emacs and other editors can do this automatically.
  • Define namespace on the .cc files;
  • Do not use "using X" directives;
  • Do not declare anything on the std namespace;
Code: namespace style on a .h file
// Note indentation
namespace octave
{
  namespace math
  {
    class foo
    {
    public:
      foo (...);
    };
  }
}
Code: namespace style on a .cc file
// Note indentation and that functions are not defined
// as "octave::math::foo:foo"
namespace octave
{
  namespace math
  {
    foo::foo (...)
    {
      ...;
    }
  }
}

Header Files

Order of Includes

Use the following order with an empty line between each section:

  1. config.h
  2. The C++ wrappers for C headers (cstdlib, cassert, etc.)
  3. C++ standard library headers (iostream, list, map, etc.)
  4. Other library header files (glpk.h, curl.h, etc., should be protected by #if defined (HAVE_FOO_H) since they may be missing on the build system)
  5. Octave's liboctave headers
  6. Octave's libinterp headers
  7. Octave's libgui headers

Other POSIX headers (sys/types.h, unistd.h, etc., should not be included directly into Octave sources. For portability, use a wrapper function. Anything you need is probably already available as a wrapper around a function or header provided by gnulib. See the files in liboctave/wrappers. This is necessary because although gnulib is great for portability, it does not generally work well with C++.

Similarly, Windows headers should not be included directly into Octave sources. Wrappers that provide the needed functionality in an OS-independent way should be used instead. This is almost always possible and there are many examples in the Octave sources.

Each grouping of header files should be alphabetized unless there is some specific reason to not do that. The only case where that is true is in oct-parse.in.yy and there is a comment in the file for that one.

There is a strict ordering of header files/libraries that must be followed. There are no exceptions to these rules:

  • The functions in liboctave/wrappers may only use headers and symbols from gnulib, standard libraries, or OS-dependent libraries. They must not use any headers or symbols from other parts of liboctave, libinterp, or libgui.
  • liboctave must not use any headers or symbols from libinterp or libgui. It must be fully functional without the interpreter or GUI.
  • libinterp must not use any headers or symbols from libgui. It must be fully functional without the GUI.

Header files should not use any "#if defined (HAVE_FEATURE)" conditionals. This is not quite true yet, but we are almost there. No new conditionals may be added.

Other C++ features

C++11

C++11 features are generally allowed. Check if the feature you want to use has been already used. If not, ask on the mailing list.

auto

Use of auto is allowed only where it helps readability and local variables.

  • Never use auto for class members.
  • Do not use auto unless the type really is obscure.
  • Beware of copy when using auto in for loops. Pass by reference and use const unless you're dealing with simple types such as int. See 'auto' uses and for-range loops on the maintainers mailing list for more details.

C++14

Do not use C++14 features. Octave is widely used in very old systems and we want them to be able to use up to date versions of Octave. Building a recent compiler in such systems is not a trivial task so the limitation must happen in Octave.

An exception: code that requires C++14 feature must also implement an alternative code in the absence of said feature. In such case, use a configure check. This increases maintenance a lot, must be used sparsely, and requires approval from other maintainers.

#if defined (HAVE_THIS_C14_FEATURE)
  // code that really needs it
#else
  // alternative code in its absence
#endif