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