C++ style guide: Difference between revisions

From Octave
Jump to navigation Jump to search
(import more text from the manual)
Line 14: Line 14:
We use spaces for indentation. Absolutely do not use tabs in your code.
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.
You should probably set your editor to emit spaces when you hit the tab key.
When indenting, indent the statement after control
structures (like {{codeline|if}}, {{codeline|while}}, etc.).  If there
is a compound statement, indent ''both'' the curly braces and the
body of the statement (so that the body gets indented by ''two''
indents).  This format is known as "GNU style" and is an option for
some code formatting tools.  Example indenting:
<pre>
if (have_args)
  {
    idx.push_back (first_args);
    have_args = false;
  }
else
  idx.push_back (make_value_list (args, arg_nm, tmp));
</pre>
If you have nested {{codeline|if}} statements, use extra braces for extra
clarification.
Split long expressions in such a way that a continuation line starts
with an operator rather than identifier.  If the split occurs inside
braces, continuation should be aligned with the first char after the
innermost braces enclosing the split.  Example:
<pre>
SVD::type type = ((nargout == 0 || nargout == 1)
                  ? SVD::sigma_only
                  : (nargin == 2) ? SVD::economy : SVD::std);
</pre>
=== Non indenting whitespace ===
Consider putting extra braces around a multi-line expression to make it
more readable, even if they are not necessary.  Also, do not hesitate to
put extra braces anywhere if it improves clarity.
The negation operator is written with a space between the operator
and its target, e.g., {{codeline|! A}}.


=== Line Length ===
=== Line Length ===
Line 20: Line 60:
readability in the widest range of environments.  This is inherited from
readability in the widest range of environments.  This is inherited from
the [https://www.gnu.org/prep/standards/standards.html#Formatting GNU Coding Standards].
the [https://www.gnu.org/prep/standards/standards.html#Formatting GNU Coding Standards].
=== Function headers ===
Format function headers like this:
<pre>
static bool
matches_patterns (const string_vector& patterns, int pat_idx,
                  int num_pat, const std::string& name)
</pre>
The return type of the function and any modifiers are specified on the first
line.  The function name on the second line should start in column 1, and
multi-line argument lists should be aligned on the first char after the open
parenthesis.  You should put a space before the left open parenthesis and after
commas, for both function definitions and function calls.


=== Namespace ===
=== Namespace ===
Line 63: Line 119:
}
}
</pre>}}
</pre>}}
== Naming ==
Use lowercase names if possible.  Uppercase is acceptable for variable
names consisting of 1-2 letters.  Do not use mixed case names.


== Header Files ==
== Header Files ==
Line 98: Line 160:
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.'''
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++ features ==


=== C++11 ===
=== C++11 features ===


C++11 features are generally allowed. Check if the feature you want to
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.
use has been already used.  If not, ask on the mailing list.


==== auto ====
=== std::string ===
 
When an empty string is required, use @qcode{""}, rather than creating an empty
string object with @code{std::string ()}.
 
=== auto ===


Use of {{codeline|auto}} is allowed only where it helps readability
Use of {{codeline|auto}} is allowed only where it helps readability
Line 131: Line 198:
   // alternative code in its absence
   // alternative code in its absence
  #endif
  #endif
== Comments ==
=== FIXME notes ===
The preferred comment mark for places that may need further attention is
with {{codeline|FIXME:}} comments.

Revision as of 18:08, 24 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.

When indenting, indent the statement after control structures (like if, while, etc.). If there is a compound statement, indent both the curly braces and the body of the statement (so that the body gets indented by two indents). This format is known as "GNU style" and is an option for some code formatting tools. Example indenting:

if (have_args)
  {
    idx.push_back (first_args);
    have_args = false;
  }
else
  idx.push_back (make_value_list (args, arg_nm, tmp));

If you have nested if statements, use extra braces for extra clarification.

Split long expressions in such a way that a continuation line starts with an operator rather than identifier. If the split occurs inside braces, continuation should be aligned with the first char after the innermost braces enclosing the split. Example:

SVD::type type = ((nargout == 0 || nargout == 1)
                  ? SVD::sigma_only
                  : (nargin == 2) ? SVD::economy : SVD::std);

Non indenting whitespace

Consider putting extra braces around a multi-line expression to make it more readable, even if they are not necessary. Also, do not hesitate to put extra braces anywhere if it improves clarity.

The negation operator is written with a space between the operator and its target, e.g., ! A.

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.

Function headers

Format function headers like this:

static bool
matches_patterns (const string_vector& patterns, int pat_idx,
                  int num_pat, const std::string& name)

The return type of the function and any modifiers are specified on the first line. The function name on the second line should start in column 1, and multi-line argument lists should be aligned on the first char after the open parenthesis. You should put a space before the left open parenthesis and after commas, for both function definitions and function calls.

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 (...)
    {
      ...;
    }
  }
}

Naming

Use lowercase names if possible. Uppercase is acceptable for variable names consisting of 1-2 letters. Do not use mixed case names.


Header Files

Order of Includes

In source files (not headers files), 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.

As much as possible, header files should be independent of other header files.

Header files must not include config.h. Instead, they should begin by including octave-config.h.

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.

C++ features

C++11 features

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.

std::string

When an empty string is required, use @qcode{""}, rather than creating an empty string object with @code{std::string ()}.

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

Comments

FIXME notes

The preferred comment mark for places that may need further attention is with FIXME: comments.