Matters Of Style

The following items are more a matter of style than the others. Nevertheless, you are asked to follow this style.

Rule: 80 columns maximum

Stick to 80 column programming. As a matter of fact, stick to 76 or 78 columns most of the time, as it makes it easier to keep the diffs within the limits. And if you post/mail these diffs, people are likely to reply to the message, hence the suggestion of 76 columns, as for emails.

Rule: Order class members by visibility first

When declaring a class, start with public members, then protected, and last private members. Inside these groups, you are invited to group by category, i.e., methods, types, and members that are related should be grouped together. The motivation is that private members should not even be visible in the class declaration (but of course, it is mandatory that they be there for the compiler), and therefore they should be “hidden” from the reader.

This is an example of what should not be done:

class Foo
{
public:
  Foo(std::string, int);
  virtual ~Foo();

private:
  using string_type = std::string;
public:
  std::string bar_get() const;
  void bar_set(std::string);
private:
  string_type bar_;

public:
  int baz_get() const;
  void baz_set(int);
private:
  int baz_;
}

rather, write:

class Foo
{
public:
  Foo(std::string, int);
  virtual ~Foo();

  std::string bar_get() const;
  void bar_set(std::string);

  int baz_get() const;
  void baz_set(int);

private:
  using string_type; = std::string
  string_type bar_;
  int baz_;
}

and add useful Doxygen comments.

Rule: Keep superclasses on the class declaration line

When declaring a derived class, try to keep its list of superclasses on the same line. Leave a space at least on the right hand side of the colon. If there is not enough room to do so, leave the colon on the class declaration line (the opposite applies for constructor, see Put initializations below the constructor declaration).

class Derived: public Base
{
  // ...
};

/// Object function to compare two Temp*.
struct temp_ptr_less
{
  bool operator()(const Temp* s1, const Temp* s2) const;
};
Rule: Don’t use inline in declarations

Use inline in implementations (i.e., *.hxx, possibly *.cc)), not during declarations (*.hh files).

Rule: Use override

If a method was once declared virtual, it remains virtual, there is no need to repeat it. However, be sure to explicitly mark it as override so that your compiler can verify it.

class Base
{
public:
  // ...
  virtual void foo() = 0;
};

class Derived: public Base
{
public:
  // ...
  void foo() override;
};
Rule: Pointers and references are part of the type

Pointers and references are part of the type, and should be put near the type, not near the variable.

int* p;        // not `int *p;'
list& l;       // not `list &l;'
void* magic(); // not `void *magic();'
Rule: Do not declare many variables on one line

Use

int* p;
int* q;

instead of

int *p, *q;

The former declarations also allow you to describe each variable.

Rule: Leave no space between template name and effective parameters

Write

std::list<int> l;
std::pair<std::list<int>, int> p;

with a space after the comma. There is no need for a space between two closing ‘>’ (since C++ 2011):

std::list<std::list<int>> ls;

These rules apply for casts:

// Come on baby, light my fire.
int* p = static_cast<int*>(42);
Rule: Leave one space between TEMPLATE and formal parameters

Write

template <class T1, class T2>
struct pair;

with one space separating the keyword template from the list of formal parameters.

Rule: Leave no space between a function name and its argument(s), either formal or actual
int
foo(int n)
{
  return bar(n);
}

The ‘()’ operator is not a list of arguments.

class Foo
{
public:
  Foo();
  virtual ~Foo();
  bool operator()(int n);
};
Rule: Put initializations below the constructor declaration

Don’t put or initializations or constructor invocations on the same line as you declare the constructor. As a matter of fact, don’t even leave the colon on that line. Instead of A::A(): B(), C(), write either:

A::A()
  : B()
  , C()
{
}

or

A::A()
  : B(), C()
{
}

The rationale is that the initialization belongs more to the body of the constructor than its signature. And when dealing with exceptions leaving the colon above would yield a result even worse than the following.

A::A()
try
  : B()
  , C()
{
}
catch (...)
{
}