Skip to content

Specification Style Guidelines

Richard Smith edited this page Mar 16, 2017 · 106 revisions

Standards Wording Idioms

This is a list of some common idioms in the standard that should be used to specify certain cases, and corresponding anti-idioms that should not be used.

When you are writing proposals for changes to the C++ standard, please try to follow these idioms. If you notice an anti-idiom in the current C++ standards draft, please [submit an editorial issue](How to submit an editorial issue).

Case Idiom(s) Anti-idiom(s) Example
Normative requirement (implementation)
Use this idiom when specifying something we require a conforming implementation to do.
  • The behavior of the program is […]
  • The implementation shall […] (only use this form when it is clear we are talking about the implementation)
  • […] must […]
  • an expression shall not have reference type

"A conforming implementation executing a well-formed program shall produce the same observable behavior as one of the possible executions of the corresponding instance of the abstract machine"
Normative requirement (program)
Use this idiom when specifying something we require a well-formed program to do, and equivalently, for something whose converse we require a conforming implementation to diagnose.
  • A prvalue shall have a complete type […]
  • The -> operator shall not be […]
  • […] must […]
  • The program is ill-formed if […] (OK, but not preferred)

"A d-char-sequence shall consist of at most 16 characters"
Normative encouragement
Use this idiom when specifying something we would prefer, but do not require, implementations to do.
  • Implementations should […]
  • Implementations are encouraged, but not required, to […]
"Implementations should ensure that all unblocked threads eventually make progress"
Complicated conditional cases
Use this idiom when you are enumerating a set of possibilities, and stating requirements under those possibilities.
  • If […], then […].
    If […], then […].

    Otherwise […]
  • […], except when […], then […], or when […], then […]
"If E1 is an lvalue, then E1.E2 is an lvalue; if E1 is an xvalue, then E1.E2 is an xvalue; otherwise, it is a prvalue."

Missing idioms

  • Variations on "ill-formed" (particularly, "no diagnostic is required" forms)

Library conventions

You can find a description of the conventions followed by the library clauses in the standard in the standard itself, in the section labeled Method of description (informative) [description] (section 17.5 in C++11).

Library-wide requirements are specified in the standard under Library-wide requirements [requirements] (section 17.6 in C++11). This section describes the type requirements (e.g. EqualityComparable and DefaultConstructible) as well as broad rules for library implementation and usage.

Writing "Let" in a function description

When describing the semantics of a library function, it's sometimes useful to introduce a new name for something, typically to shorten it. In that case, write a paragraph ahead of the Effects, Returns, and similar paragraphs to do so.

For example:

  1. Let T be decltype(foo).
  2. Returns: T{0}.
  3. Requires: T shall be CopyConstructible.

Do not put a "Let" statement in the Remarks paragraph of a function description.

Writing Effects: in a function description

Effects: elements are used in the library to describe functions. They can be described in words, or in code preceded by an introductory phrase of some kind. The introductory phase "Equivalent to" is normative and has special meaning, as is described in [structure.specifications]/4. When code is used to describe an effects element, a colon (:) should follow the introductory phrase if the code is a statement or a code block, where as expressions should end with a period (.).

For example:

  1. Effects: The function works in this way.

  2. Effects: Equivalent to expression.

  3. Effects: Equivalent to:

     statement1;
     statement2;
    

Note that return 42 is not an expression (it's not an anything -- the return grammar production has a trailing ;), so this is wrong:

Effects: Equivalent to return 42.

and these are acceptable:

Effects: Equivalent to: return 42;

Effects: Equivalent to:

    return 42;

Writing Returns: in a function description

Returns: elements are similar to Effects: elements. They should always end in a full stop. They may be just a single expression, or phrase or sentence. If the text starts with normal text, it should be capitalized. Very long expressions may use a codeblock (without a full stop at the end).

For example:

  1. Returns: !(a == b).

  2. Returns: true if foo; false otherwise.

  3. Returns: A copy of the object described in this sentence.

  4. Returns:

     a_very_long_expression()
    

Specifying implicitly generated special member functions

When you are specifying a class containing implicitly generated member functions, do not provide a detailed specification of these, as their behavior is implied by the language rules. Instead, list the member functions using the = default mechanism in the class synopsis only. For example:

class my_class {
  // ...
public:
  my_class() noexcept = default;
  my_class(const my_class&) = default;
  my_class& operator=(const my_class&) = default;
  my_class(my_class&&) noexcept = default;
  my_class& operator=(my_class&&) noexcept = default;
  ~my_class() noexcept = default;
  // ...
};

Formatting declarations and definitions

These rules apply within library clauses. Within core clauses, we intentionally use a variety of different styles to emphasize that the core language does not enforce any particular style.

  • Use two-space indentation when breaking a declaration after a template-head or return type; indent to the active < or ( when breaking within a template or function parameter list.
  • Template parameter names are camel-case.
  • Template type parameters use class not typename.
  • const goes to the left of the type it modifies.
  • &, *, ::*, and ... have no space on their left-hand side, and have a space on their right-hand side unless another operator appears next.
  • Do not insert whitespace between operator and the following token except in a conversion-type-id. Examples: operator(), operator""if, but operator (int(*)()).

Source code formatting

A typical paragraph of LaTeX should use the following conventions:

\pnum                                          %% start with \pnum
\indextext{...}%                               %% relevant paragraph-wide entries,
\indextext{...}%                               %% one per line; no whitespace!
Lorem ipsum first sentence here, defining a
\defn{thing}\indextext{alternate entry}. When
needed,\footnote{mind the spacing} add
a footnote.
\begin{itemize}                                %% No blank line before!
\item Short item 1
\item Short item 2
\item Short item 3
\end{itemize}                                  %% begin and end on their
\begin{note}                                   %% own lines if possible
This is not normative.
\begin{example}
\begin{codeblock}
/* ... */
\end{codeblock}
\end{example}
You can nest examples in notes, or keep them as
consecutive siblings.
\end{note}
This is a very long paragraph, which is not great,
but we want to show off another list:
\begin{itemize}
\item
  For longer list items, indent each item by two.
  No additional blank lines are needed.
\item
  With this style, nested lists are easy as pie.
  \begin{itemize}
  \item Same rules as for all lists,
  \item recursively.
  \end{itemize}
\item
  We have too many lists
  in the Standard.
\end{itemize}
Finally this paragraph is coming to an end.

Code blocks

Codeblocks follow some loose conventions. Indentation is by two spaces. Indentation is applied when a function declaration contains linebreaks after the template signature or the return type:

template <typename T> void foo(T);

template <typename T, typename Iter>
  std::vector<T> a_longer_function_name(Iter first, Iter last, T& out);

template <typename T, typename Iter>
  std::vector<std::iterator_traits<Iter>::allocator_type, const T*>
    a_hypnotically_longer_function(Iter first, Iter last, const T& in, T& out) noexcept;

In example code, line comments (//) are indented according to certain rules:

  1. The comment column number must always be a multiple of 4.
  2. There must be at least one space between code and comment.
  3. If possible, there should be at least two spaces between code and comment.
  4. We have a strong preference for columns 20, 32 and 40. Text within a region (e.g. a spread or two) may try for a common column. If there is a column value that works well except in a handful of isolated cases, Rule 3 may be violated to accommodate this.

ISO Directives

Rules for the overall structure and form of ISO standards is provided by the ISO Directives, Part 2. This covers rules common to all ISO documents, such as the meaning of should and shall, and the referencing of other standards documents. However, the C++ standard provides requirements at two levels simultaneously (for a conforming implementation and for a well-formed program), and these terms are usually repurposed as describing the language rather than the implementation.

Among others, these directives also define the following terms (note capitalization):

  • "International Standard" (standard issued by ISO or IEC); use the phrase "this International Standard" when referring to the C++ standard from within the document itself.

LaTeX macro usage

As a general rule, formatting macros should describe the semantics, not the desired visual outcome. For example, \textit is discouraged over \placeholder or \grammarterm.

  • \cv{} renders as cv (denoting a possibly empty set of cv-qualifiers)
  • \cvqual{cv1} renders as cv1 (see cv)

Formatting

  • $\tcode{T}_i$ to refer to an indexed type "Ti", for example the i-th type in a parameter pack. Example: [func.bind.bind]
  • $i^\text{th}$ to spell "i-th"

Spelling conventions

Capitalization

  • Section headings are sentence case, not title case.
  • "[ Note:" and "[ Example:" are not considered to begin a sentence, so the following word should be capitalized as the start of a sentence. Likewise, footnotes should be complete sentences or at least sentence fragments, and should be capitalized as such.

Hyphens: nonX vs. non-X

  • For technical terms defined by the C++ standard, where "nonX" is either not an English word or not one with the right meaning, use a hyphen: non-abstract, non-class, non-const, non-constant, non-empty (when referring to empty classes), non-member, non-trivial (when referring to special member triviality).
  • For plain English words where the "nonX" form is well-established (when the closed form is listed in a common dictionary), do not use a hyphen: nondeterministic, nonempty (when referring to sets), nontrivial (when referring to the difficulty of doing something), and nonzero.
  • For plain English words where the "nonX" form is not established, use a hyphen: non-graphic, non-portable.

Indexes

  • Do not use the tilde (non-breaking space) in index entries. Decided in #1064.
Clone this wiki locally