Update C++ style guide (#971)
- Ban forward declaration of entities not owned by the project.
- Recommend `absl::down_cast` for downcasting instead of `static_cast`.
- Expanded and reworked guidance on `auto` for variables and function
parameters: in particular, encourage structured bindings for map-like
containers.
- Remove Boost section and add a section for third-party libraries with
general guidance.
- Other minor updates and improvements to wording, et cetera.
diff --git a/cppguide.html b/cppguide.html
index 7c6db3c..c5c7b98 100644
--- a/cppguide.html
+++ b/cppguide.html
@@ -346,8 +346,21 @@
</ul>
<p class="decision"></p>
-<p>Try to avoid forward declarations of entities
-defined in another project.</p>
+<p>Do not use forward declarations of entities that your project
+ does not own.</p>
+
+<p>For entities that you do own:
+ </p><ul>
+ <li>Try to make the header for a declaration cheap enough
+ to easily include it directly.</li>
+
+ <li>If the full header is too expensive to include,
+ try to speed up the header's compilation.</li>
+
+ <li>If your best engineering judgment is that a forward
+ declaration is a better way to fix a slowdown, exercise
+ that judgment and use a forward declaration.</li>
+ </ul>
<a id="Inline_Functions"></a>
<h3 id="Defining_Functions_in_Header_Files">Defining Functions in Header Files</h3>
@@ -718,7 +731,7 @@
namespace internal { // Internal, not part of the API.
namespace sidetable = ::pipeline_diagnostics::sidetable;
-} // namespace internal
+}
inline void my_inline_function() {
// Local to a function.
@@ -1583,7 +1596,7 @@
inheritance".</p>
<p class="pros"></p>
-<p>Implementation inheritance reduces code size by re-using
+<p>Implementation inheritance reduces code size by reusing
the base class code as it specializes an existing type.
Because inheritance is a compile-time declaration, you
and the compiler can understand the operation and detect
@@ -1880,7 +1893,9 @@
bugs. Instead, find a way to eliminate the lifetime requirement
(for example, by copying the parameter), or pass retained parameters by
pointer and document the lifetime and non-null requirements.
-See <a href="https://abseil.io/tips/116">TotW 116</a> for more.</p>
+See <a href="https://abseil.io/tips/116">TotW 116</a> for more.
+
+</p>
<p>When ordering function parameters, put all input-only
parameters before any output parameters. In particular,
@@ -2091,6 +2106,33 @@
+<h3 id="cpplint">cpplint</h3>
+
+<p>Use <code>cpplint.py</code> to detect style errors.</p>
+
+<p><code>cpplint.py</code>
+is a tool that reads a source file and identifies many
+style errors. It is not perfect, and has both false
+positives and false negatives, but it is still a valuable
+tool. </p>
+
+
+
+<div>
+<p>Some projects have instructions on
+how to run <code>cpplint.py</code> from their project
+tools. If the project you are contributing to does not,
+you can download
+<a href="https://raw.githubusercontent.com/cpplint/cpplint/HEAD/cpplint.py">
+<code>cpplint.py</code></a> separately.</p>
+</div>
+
+
+
+
+
+<h2 id="Other_C++_Features">Other C++ Features</h2>
+
<h3 id="Ownership_and_Smart_Pointers">Ownership and Smart Pointers</h3>
<p>Prefer to have single, fixed owners for dynamically
@@ -2218,31 +2260,6 @@
<p>Never use <code>std::auto_ptr</code>. Instead, use
<code>std::unique_ptr</code>.</p>
-<h3 id="cpplint">cpplint</h3>
-
-<p>Use <code>cpplint.py</code> to detect style errors.</p>
-
-<p><code>cpplint.py</code>
-is a tool that reads a source file and identifies many
-style errors. It is not perfect, and has both false
-positives and false negatives, but it is still a valuable
-tool. </p>
-
-
-
-<div>
-<p>Some projects have instructions on
-how to run <code>cpplint.py</code> from their project
-tools. If the project you are contributing to does not,
-you can download
-<a href="https://raw.githubusercontent.com/cpplint/cpplint/HEAD/cpplint.py">
-<code>cpplint.py</code></a> separately.</p>
-</div>
-
-
-
-<h2 id="Other_C++_Features">Other C++ Features</h2>
-
<h3 id="Rvalue_references">Rvalue References</h3>
<p>Use rvalue references only in certain special cases listed below.</p>
@@ -2292,7 +2309,7 @@
<p class="cons"></p>
<ul>
- <li>Rvalue references are not yet widely understood. Rules like reference
+ <li>Rvalue references are not widely understood. Rules like reference
collapsing and the special deduction rule for forwarding references
are somewhat obscure.</li>
@@ -2621,11 +2638,13 @@
instance of a base class is in fact an instance of a
particular derived class, then a
<code>dynamic_cast</code> may be used freely on the
-object. Usually one
-can use a <code>static_cast</code> as an alternative in
-such situations.</p>
+object. Usually
-<p>Decision trees based on type are a strong indication
+<a href="https://github.com/abseil/abseil-cpp/blob/master/absl/base/casts.h">
+<code>absl::down_cast</code></a> provides an even better
+alternative.
+
+</p><p>Decision trees based on type are a strong indication
that your code is on the wrong track.</p>
<pre class="badcode">if (typeid(*data) == typeid(D1)) {
@@ -2676,7 +2695,12 @@
<p class="decision"></p>
<p>In general, do not use C-style casts. Instead, use these C++-style
casts when explicit type conversion is necessary.
-</p>
+Some are part of the standard C++ language,
+and some are defined in
+
+<a href="https://github.com/abseil/abseil-cpp/blob/master/absl/base/casts.h">
+ <code>absl/base/casts.h</code></a>. Use the first that
+<b>correctly applies</b>:</p>
<ul>
<li>Use brace initialization to convert arithmetic types
@@ -2704,7 +2728,10 @@
subclass. In this last case, you must be sure your object is
actually an instance of the subclass.</li>
-
+ <li>Use <code>absl::down_cast</code>
+ to cast a pointer from a superclass
+ to a subclass. You must be sure your object is actually
+ an instance of the subclass.</li>
<li>Use <code>const_cast</code> to remove the
<code>const</code> qualifier (see <a href="#Use_of_const">const</a>).</li>
@@ -3029,9 +3056,7 @@
<code>int64_t</code>, etc. You should always use
those in preference to <code>short</code>, <code>unsigned
long long</code>, and the like, when you need a guarantee
-on the size of an integer. Prefer to omit the <code>std::</code>
-prefix for these types, as the extra 5 characters do
-not merit the added clutter. Of the built-in integer types, only
+on the size of an integer. Of the built-in integer types, only
<code>int</code> should be used. When appropriate, you
are welcome to use standard type aliases like
<code>size_t</code> and <code>ptrdiff_t</code>.</p>
@@ -3061,6 +3086,9 @@
+<p>Prefer to omit the <code>std::</code> prefix on standard library
+integer types, as the extra 5 characters do not merit the added clutter.</p>
+
<p>If your code is a container that returns a size, be
sure to use a type that will accommodate any possible
usage of your container. When in doubt, use a larger type
@@ -3282,6 +3310,10 @@
void f(T t);
f(0); // Invokes f<int>(0)</pre>
+ A lambda expression can also have template parameters, which are deduced in the same way:
+ <pre class="neutralcode">// Sort `vec` in decreasing order
+std::sort(vec.begin(), vec.end(), []<typename T>(T lhs, T rhs) { return lhs > rhs; });
+</pre>
</dd>
<dt><a href="https://en.cppreference.com/w/cpp/language/auto"><code>auto</code> variable declarations</a></dt>
<dd>A variable declaration can use the <code>auto</code> keyword in place
@@ -3316,11 +3348,10 @@
rely on type deduction; it's just an alternative syntax for an explicit
return type.
</dd>
- <dt><a href="https://isocpp.org/wiki/faq/cpp14-language#generic-lambdas">Generic lambdas</a></dt>
- <dd>A lambda expression can use the <code>auto</code> keyword in place of
- one or more of its parameter types. This causes the lambda's call operator
- to be a function template instead of an ordinary function, with a separate
- template parameter for each <code>auto</code> function parameter:
+ <dt><a href="https://en.cppreference.com/w/cpp/language/auto.html"><code>auto</code> parameters</a></dt>
+ <dd>A function or lambda expression can use the <code>auto</code> keyword in place of
+ one or more of its parameter types. This causes it to be a function template instead of an
+ ordinary function, with a separate template parameter for each <code>auto</code> function parameter:
<pre class="neutralcode">// Sort `vec` in decreasing order
std::sort(vec.begin(), vec.end(), [](auto lhs, auto rhs) { return lhs > rhs; });</pre>
</dd>
@@ -3447,10 +3478,18 @@
Note that class template argument deduction is also subject to a
<a href="#CTAD">separate style rule</a>.</p>
+<p>Explicit types for elements of <code>map</code>-like containers are easy to
+ get wrong. In those cases <a href="#Structured_Bindings">structured
+ bindings</a> for the key and value are almost always clearer than a single
+ variable representing the pair.</p>
+
<p>Do not use <code>decltype(auto)</code> if a simpler option will work;
because it's a fairly obscure feature, it has a high cost in code
clarity.</p>
+<p> See <a href="https://abseil.io/tips/232">TotW #232</a> for more details on
+ when to use <code>auto</code> for variable declarations.</p>
+
<h4>Return type deduction</h4>
<p>Use return type deduction (for both functions and lambdas) only if the
@@ -3462,16 +3501,30 @@
<em>is</em> the interface. In particular, public functions in header files
should almost never have deduced return types.</p>
-<h4>Parameter type deduction</h4>
+<h4>Function parameter type deduction</h4>
-<p><code>auto</code> parameter types for lambdas should be used with caution,
- because the actual type is determined by the code that calls the lambda,
- rather than by the definition of the lambda. Consequently, an explicit
- type will almost always be clearer unless the lambda is explicitly called
- very close to where it's defined (so that the reader can easily see both),
- or the lambda is passed to an interface so well-known that it's
- obvious what arguments it will eventually be called with (e.g.,
- the <code>std::sort</code> example above).</p>
+<p>Avoid using parameter type deduction (using either <code>auto</code> or template
+ parameters) if you can give the parameter a specific type instead. If it will only
+ be called with one type, it will almost always be clearer to make that type explicit,
+ unless it is called very close to where it's defined (so that the reader can easily
+ see both), or it's a lambda being passed to an interface so well-known that it's
+ obvious what type it will eventually be called with (e.g., the <code>std::sort</code>
+ example above)</p>
+
+<p>Do not use <code>auto</code> parameters in non-lambda functions. Use named template parameters
+ instead, because they are more explicit about the fact that the function is a template:</p>
+ <pre class="badcode">void F(auto arg) { ... }
+</pre>
+<pre class="goodcode">template <typename T>
+void F(T arg) { ... }
+</pre>
+
+<p>In a lambda expression, if you need to refer to the type of a parameter, prefer to make that
+ type a template parameter:</p>
+ <pre class="badcode">[](auto x) { decltype(x) y; ... }
+</pre>
+ <pre class="goodcode">[]<typename T>(T x) { T y; ... }
+</pre>
<h4>Lambda init captures</h4>
@@ -3492,6 +3545,13 @@
pairs or tuples</a> unless a pre-existing API like <code>insert</code>
forces you to.</p>
+<p>The elements of containers like <code>std::map<K, V></code> benefit
+ especially from structured bindings; not only can the two parts of the pair be
+ given more specific names, but the use of type deduction dodges the common bug
+ of failing to <code>const</code>-qualify the key type of the element, which
+ often surprisingly succeeds in compiling by introducing unintended
+ copying.</p>
+
<p>If the object being bound is a struct, it may sometimes be helpful to
provide names that are more specific to your usage, but keep in mind that
this may also mean the names are less recognizable to your reader than the
@@ -4016,115 +4076,12 @@
project-wide use by your project leads. Do not roll your own promise or
awaitable types.</p>
-<h3 id="Boost">Boost</h3>
-
-<p>Use only approved libraries from the Boost library
-collection.</p>
-
-<p class="definition"></p>
-<p> The
-<a href="https://www.boost.org/">
-Boost library collection</a> is a popular collection of
-peer-reviewed, free, open-source C++ libraries.</p>
-
-<p class="pros"></p>
-<p>Boost code is generally very high-quality, is widely
-portable, and fills many important gaps in the C++
-standard library, such as type traits and better binders.</p>
-
-<p class="cons"></p>
-<p>Some Boost libraries encourage coding practices which can
-hamper readability, such as metaprogramming and other
-advanced template techniques, and an excessively
-"functional" style of programming. </p>
-
-<p class="decision"></p>
-
-
-
-<div>
-<p>In order to maintain a high level of readability for
-all contributors who might read and maintain code, we
-only allow an approved subset of Boost features.
-Currently, the following libraries are permitted:</p>
-
-<ul>
- <li>
- <a href="https://www.boost.org/libs/utility/call_traits.htm">
- Call Traits</a> from <code>boost/call_traits.hpp</code></li>
-
- <li><a href="https://www.boost.org/libs/utility/compressed_pair.htm">
- Compressed Pair</a> from <code>boost/compressed_pair.hpp</code></li>
-
- <li><a href="https://www.boost.org/libs/graph/">
- The Boost Graph Library (BGL)</a> from <code>boost/graph</code>,
- except serialization (<code>adj_list_serialize.hpp</code>) and
- parallel/distributed algorithms and data structures
- (<code>boost/graph/parallel/*</code> and
- <code>boost/graph/distributed/*</code>).</li>
-
- <li><a href="https://www.boost.org/libs/property_map/">
- Property Map</a> from <code>boost/property_map</code>, except
- parallel/distributed property maps (<code>boost/property_map/parallel/*</code>).</li>
-
- <li><a href="https://www.boost.org/libs/iterator/">
- Iterator</a> from <code>boost/iterator</code></li>
-
- <li>The part of <a href="https://www.boost.org/libs/polygon/">
- Polygon</a> that deals with Voronoi diagram
- construction and doesn't depend on the rest of
- Polygon:
- <code>boost/polygon/voronoi_builder.hpp</code>,
- <code>boost/polygon/voronoi_diagram.hpp</code>, and
- <code>boost/polygon/voronoi_geometry_type.hpp</code></li>
-
- <li><a href="https://www.boost.org/libs/bimap/">
- Bimap</a> from <code>boost/bimap</code></li>
-
- <li><a href="https://www.boost.org/libs/math/doc/html/dist.html">
- Statistical Distributions and Functions</a> from
- <code>boost/math/distributions</code></li>
-
- <li><a href="https://www.boost.org/libs/math/doc/html/special.html">
- Special Functions</a> from <code>boost/math/special_functions</code></li>
-
- <li><a href="https://www.boost.org/libs/math/doc/html/root_finding.html">
- Root Finding & Minimization Functions</a> from <code>boost/math/tools</code></li>
-
- <li><a href="https://www.boost.org/libs/multi_index/">
- Multi-index</a> from <code>boost/multi_index</code></li>
-
- <li><a href="https://www.boost.org/libs/heap/">
- Heap</a> from <code>boost/heap</code></li>
-
- <li>The flat containers from
- <a href="https://www.boost.org/libs/container/">Container</a>:
- <code>boost/container/flat_map</code>, and
- <code>boost/container/flat_set</code></li>
-
- <li><a href="https://www.boost.org/libs/intrusive/">Intrusive</a>
- from <code>boost/intrusive</code>.</li>
-
- <li><a href="https://www.boost.org/libs/sort/">The
- <code>boost/sort</code> library</a>.</li>
-
- <li><a href="https://www.boost.org/libs/preprocessor/">Preprocessor</a>
- from <code>boost/preprocessor</code>.</li>
-</ul>
-
-<p>We are actively considering adding other Boost
-features to the list, so this list may be expanded in
-the future.</p>
-</div>
-
-
<h3 id="Disallowed_Stdlib">Disallowed standard library features</h3>
-<p>As with <a href="#Boost">Boost</a>, some modern C++
-library functionality encourages coding practices that hamper
+<p>Some modern C++ library functionality encourages coding practices that hamper
readability — for example by removing
checked redundancy (such as type names) that may be
helpful to readers, or by encouraging template
@@ -4155,6 +4112,51 @@
</ul>
+<h3 id="Third_party_Libraries">Third-party Libraries</h3>
+
+<p>When choosing to use third-party libraries, be consistent with the code
+ around you.</p>
+
+<p class="definition"></p>
+<p>A third-party library is a library that is not primarily developed in the
+ same repository as your code.</p>
+
+<p class="pros"></p>
+<ul>
+ <li>Reusing high-quality third-party libraries can avoid vast amounts of
+ work duplicating their functionality.</li>
+ <li>Some third-party libraries are so well-established in their problem
+ domain that avoiding them would actually make the code harder to read.</li>
+</ul>
+
+<p class="cons"></p>
+<ul>
+ <li>Third-party libraries may have different programming practices than ours.
+ In some cases this can be "viral", making it harder for code that uses the
+ library to follow our style and programming practices.</li>
+ <li>Third-party libraries can carry many hidden support burdens, such as license
+ compliance, monitoring and patching vulnerabilities, and dealing with breaking
+ changes from upstream.</li>
+</ul>
+
+<p class="decision"></p>
+<p>When choosing a library to solve a particular problem, first check if there's
+ already a library that your codebase typically uses for that kind of problem.
+ If so, use it. If not, prefer libraries from the following sources, in roughly
+ decreasing order of priority:</p>
+
+<ul>
+ <li><a href="https://abseil.io/">Abseil</a>
+ .</li>
+ <li>The C++ standard library (except as discussed <a href="#Disallowed_Stdlib">here</a>)</li>
+ <li>Existing first-party libraries in the codebase.</li>
+ <li>Third-party libraries</li>
+</ul>
+
+<p>If you choose to use a third-party library, make sure to follow
+
+ your codebase's policies for third-party code.</p>
+
<h3 id="Nonstandard_Extensions">Nonstandard Extensions</h3>
<p>Nonstandard extensions to C++ may not be used unless otherwise specified.</p>
@@ -4546,7 +4548,7 @@
private:
std::string table_name_; // OK - underscore at end.
- static Pool<TableInfo>* pool_; // OK.
+ static Pool<TableInfo>* absl_nullable pool_; // OK.
};
</pre>
@@ -4559,7 +4561,7 @@
<pre class="goodcode">struct UrlTableProperties {
std::string name;
int num_entries;
- static Pool<UrlTableProperties>* pool;
+ static Pool<UrlTableProperties>* absl_nullable pool;
};
</pre>
@@ -4846,8 +4848,10 @@
call. This is quite common for pointer/reference arguments to
constructors.</li>
- <li>For each pointer argument, whether it is allowed to be null and what happens
- if it is.</li>
+ <li>For each pointer argument, whether it is allowed
+ to be null and what happens if it is.</li>
+
+
<li>For each output or input/output argument, what happens to any state that argument
is in (e.g., is the state appended to or overwritten?).
@@ -5651,6 +5655,8 @@
std::vector<char*> // Note no space between '*' and '>'
</pre>
+
+
<p>It is allowed (if unusual) to declare multiple variables in the same
declaration, but it is disallowed if any of those have pointer or
reference decorations. Such declarations are easily misread.</p>
@@ -5792,11 +5798,12 @@
public: // Note the 1 space indent!
MyClass(); // Regular 2 space indent.
explicit MyClass(int var);
+ MyClass(const MyClass& other);
+ MyClass& operator=(const MyClass& other);
~MyClass() {}
void SomeFunction();
- void SomeFunctionThatDoesNothing() {
- }
+ void SomeFunctionThatDoesNothing() {}
void set_some_var(int var) { some_var_ = var; }
int some_var() const { return some_var_; }