From 7a7a2f510efe7d7fc5ea8fbed549ddb31fac8f3e Mon Sep 17 00:00:00 2001 From: Daniel Cheng Date: Tue, 19 May 2020 22:52:15 +0000 Subject: [PATCH] Update C++ styleguide Major changes: - discourage const references when the input parameter must outlive the call - drop ban on mutable references - allow rvalue-qualified methods in certain situations - allow C-style cast when casting to void - disallow postfix increment/decrement operators unless postfix semantics are required - allow designated initializers in C++20-compliant form - disallow macro-style naming for enumerator constant for new code - disallow spaces inside parentheses for conditionals The change itself is largely automated, with a few manual adjustments: - manually restore the TOC placeholder - removed trailing whitespace --- cppguide.html | 548 +++++++++++++++++++++++--------------------------- 1 file changed, 256 insertions(+), 292 deletions(-) diff --git a/cppguide.html b/cppguide.html index bbf1f64..ef844b5 100644 --- a/cppguide.html +++ b/cppguide.html @@ -10,9 +10,6 @@

Google C++ Style Guide

-
-
-

C++ is one of the main development languages used by @@ -64,10 +61,10 @@ must be large enough to justify asking all of our engineers to remember it. The benefit is measured relative to the codebase we would get without the rule, so a rule against a very harmful practice may still have a small benefit if people are unlikely to do it -anyway. This principle mostly explains the rules we don’t have, rather +anyway. This principle mostly explains the rules we don’t have, rather than the rules we do: for example, goto contravenes many of the following principles, but is already vanishingly rare, so the Style -Guide doesn’t discuss it. +Guide doesn’t discuss it.

Optimize for the reader, not the writer
Our codebase (and most individual components submitted to it) is @@ -176,9 +173,8 @@ before using features from C++14 and C++17 in your project.

In general, every .cc file should have an associated .h file. There are some common -exceptions, such as unittests and -small .cc files containing just a -main() function.

+exceptions, such as unit tests and small .cc files containing +just a main() function.

Correct use of header files can make a huge difference to the readability, size and performance of your code.

@@ -291,16 +287,16 @@ function, or template without an associated definition.

Replacing an #include with a forward declaration can silently change the meaning of code: -
      // b.h:
-      struct B {};
-      struct D : B {};
+
// b.h:
+struct B {};
+struct D : B {};
 
-      // good_user.cc:
-      #include "b.h"
-      void f(B*);
-      void f(void*);
-      void test(D* x) { f(x); }  // calls f(B*)
-      
+// good_user.cc: +#include "b.h" +void f(B*); +void f(void*); +void test(D* x) { f(x); } // calls f(B*) +
If the #include was replaced with forward decls for B and D, test() would call f(void*). @@ -311,7 +307,7 @@ function, or template without an associated definition.

#includeing the header.
  • Structuring code to enable forward declarations - (e.g. using pointer members instead of object members) + (e.g., using pointer members instead of object members) can make the code slower and more complex.
  • @@ -409,12 +405,12 @@ as follows:

  • A blank line
  • C system headers (more precisely: headers in angle brackets with the - .h extension), e.g. <unistd.h>, + .h extension), e.g., <unistd.h>, <stdlib.h>.
  • A blank line
  • -
  • C++ standard library headers (without file extension), e.g. +
  • C++ standard library headers (without file extension), e.g., <algorithm>, <cstddef>.
  • A blank line
  • @@ -440,7 +436,7 @@ people in other packages.

    dir/foo.cc and dir2/foo2.h are usually in the same -directory (e.g. base/basictypes_test.cc and +directory (e.g., base/basictypes_test.cc and base/basictypes.h), but may sometimes be in different directories too.

    @@ -503,7 +499,7 @@ system-specific code small and localized. Example:

    With few exceptions, place code in a namespace. Namespaces should have unique names based on the project name, and possibly -its path. Do not use using-directives (e.g. +its path. Do not use using-directives (e.g., using namespace foo). Do not use inline namespaces. For unnamed namespaces, see Unnamed Namespaces and @@ -700,7 +696,7 @@ Do not use internal linkage in .h files.

    Nonmember, Static Member, and Global Functions

    Prefer placing nonmember functions in a namespace; use completely global -functions rarely. Do not use a class simply to group static functions. Static +functions rarely. Do not use a class simply to group static members. Static methods of a class should generally be closely related to instances of the class or the class's static data.

    @@ -721,8 +717,8 @@ function not bound to a class instance. Such a function can be either a static member or a nonmember function. Nonmember functions should not depend on external variables, and should nearly always exist in a namespace. -Do not create classes only to group static member functions; -this is no different than just giving the function names a +Do not create classes only to group static members; +this is no different than just giving the names a common prefix, and such grouping is usually unnecessary anyway.

    If you define a nonmember function and it is only @@ -741,7 +737,7 @@ scope as possible, and as close to the first use as possible. This makes it easier for the reader to find the declaration and see what type the variable is and what it was initialized to. In particular, initialization should -be used instead of declaration and assignment, e.g.:

    +be used instead of declaration and assignment, e.g.,:

    int i;
     i = f();      // Bad -- initialization separate from declaration.
    @@ -954,8 +950,8 @@ does not make an observable difference. For example:

    collection, such as a set to search against or a lookup table, you cannot use the dynamic containers from the standard library as a static variable, since they have non-trivial destructors. Instead, consider a simple array of - trivial types, e.g. an array of arrays of ints (for a "map from int to - int"), or an array of pairs (e.g. pairs of int and const + trivial types, e.g., an array of arrays of ints (for a "map from int to + int"), or an array of pairs (e.g., pairs of int and const char*). For small collections, linear search is entirely sufficient (and efficient, due to memory locality); consider using the facilities from @@ -975,7 +971,7 @@ does not make an observable difference. For example:

    a type that you need to define yourself, give the type a trivial destructor and a constexpr constructor.
  • If all else fails, you can create an object dynamically and never delete - it by using a function-local static pointer or reference (e.g. static + it by using a function-local static pointer or reference (e.g., static const auto& impl = *new T(args...);).
  • @@ -1053,7 +1049,7 @@ variables.

    thread_local variables at class or namespace scope must be -initialized with a true compile-time constant (i.e. they must have no +initialized with a true compile-time constant (i.e., they must have no dynamic initialization). To enforce this, thread_local variables at class or namespace scope must be annotated with @@ -1147,7 +1143,7 @@ type) is expected, such as when passing an users can define their own, by adding appropriate members to the class definition of the source or destination type. An implicit conversion in the source type is defined by a type conversion operator -named after the destination type (e.g. operator +named after the destination type (e.g., operator bool()). An implicit conversion in the destination type is defined by a constructor that can take the source type as its only argument (or only argument with no default value).

    @@ -1155,7 +1151,7 @@ its only argument (or only argument with no default value).

    The explicit keyword can be applied to a constructor or (since C++11) a conversion operator, to ensure that it can only be used when the destination type is explicit at the point of use, -e.g. with a cast. This applies not only to implicit conversions, but to +e.g., with a cast. This applies not only to implicit conversions, but to C++11's list initialization syntax:

    class Foo {
       explicit Foo(int x, double y);
    @@ -1202,8 +1198,11 @@ language treats it as one as far as explicit is concerned.
         it's intended to define an implicit conversion, or the author
         simply forgot to mark it.
     
    -
  • It's not always clear which type should provide the conversion, - and if they both do, the code becomes ambiguous.
  • +
  • Implicit conversions can lead to call-site ambiguities, especially + when there are bidirectional implicit conversions. This can be caused + either by having two types that both provide an implicit conversion, + or by a single type that has both an implicit constructor and an + implicit type conversion operator.
  • List initialization can suffer from the same problems if the destination type is implicit, particularly if the @@ -1216,17 +1215,21 @@ callable with a single argument, must be marked explicit in the class definition. As an exception, copy and move constructors should not be explicit, since they do not perform type -conversion. Implicit conversions can sometimes be necessary and -appropriate for types that are designed to transparently wrap other -types. In that case, contact -your project leads to request -a waiver of this rule.

    +conversion.

    + +

    Implicit conversions can sometimes be necessary and appropriate for +types that are designed to be interchangeable, for example when objects +of two types are just different representations of the same underlying +value. In that case, contact +your project leads to request a waiver +of this rule. +

    Constructors that cannot be called with a single argument may omit explicit. Constructors that take a single std::initializer_list parameter should also omit explicit, in order to support copy-initialization -(e.g. MyType m = {1, 2};).

    +(e.g., MyType m = {1, 2};).

    Copyable and Movable Types

    @@ -1256,7 +1259,7 @@ move constructor and the move-assignment operator, if they exist, or by the copy constructor and the copy-assignment operator otherwise.

    The copy/move constructors can be implicitly invoked by the compiler -in some situations, e.g. when passing objects by value.

    +in some situations, e.g., when passing objects by value.

    Objects of copyable and movable types can be passed and returned by value, @@ -1397,14 +1400,12 @@ appropriate keyword for the data-type you're defining.

    structs should be used for passive objects that carry -data, and may have associated constants, but lack any functionality -other than access/setting the data members. All fields must be public, -and accessed directly rather than through getter/setter methods. The +data, and may have associated constants. All fields must be public. The struct must not have invariants that imply relationships between -different fields, since direct user access to those fields may break -those invariants. Methods should not provide behavior but should only -be used to set up the data members, e.g., constructor, destructor, -Initialize(), Reset().

    +different fields, since direct user access to those fields may +break those invariants. Constructors, destructors, and helper methods may +be present; however, these methods must not require or enforce any +invariants.

    If more functionality or invariants are required, a class is more appropriate. If in doubt, make @@ -1535,7 +1536,7 @@ such as operator bool().

    Operator overloading can make code more concise and intuitive by enabling user-defined types to behave the same as built-in types. Overloaded operators are the idiomatic names -for certain operations (e.g. ==, <, +for certain operations (e.g., ==, <, =, and <<), and adhering to those conventions can make user-defined types more readable and enable them to interoperate with libraries that expect @@ -1563,7 +1564,7 @@ creating objects of user-defined types.

  • Finding the call sites for overloaded operators may require a search tool that's aware of C++ syntax, rather - than e.g. grep.
  • + than e.g., grep.
  • If you get the argument type of an overloaded operator wrong, you may get a different overload rather than a @@ -1641,7 +1642,7 @@ use a custom comparator rather than overloading

    Do not overload &&, ||, , (comma), or unary &. Do not overload -operator"", i.e. do not introduce user-defined +operator"", i.e., do not introduce user-defined literals. Do not use any such literals provided by others (including the standard library).

    @@ -1661,12 +1662,14 @@ apply to operator overloading as well.

    of some easy boilerplate in the form of accessors (usually const) if necessary.

    For technical -reasons, we allow data members of a test fixture class in a .cc file to +reasons, we allow data members of a test fixture class defined in a .cc file to be protected when using Google -Test).

    +Test). +If a test fixture class is defined outside of the .cc file it is used in, for example in a .h file, +make data members private.

    Declaration Order

    @@ -1682,7 +1685,7 @@ sections that would be empty.

    kinds of declarations together, and generally prefer the following order: types (including typedef, using, and nested structs and classes), -constants, factory functions, constructors, assignment +constants, factory functions, constructors and assignment operators, destructor, all other methods, data members.

    Do not put large method definitions inline in the @@ -1694,31 +1697,41 @@ Functions for more details.

    Functions

    -

    Output Parameters

    + +

    Inputs and Outputs

    The output of a C++ function is naturally provided via -a return value and sometimes via output parameters.

    +a return value and sometimes via output parameters (or in/out parameters).

    Prefer using return values over output parameters: they improve readability, and often provide the same or better -performance. If output-only parameters are used, -they should appear after input parameters.

    +performance.

    Parameters are either input to the function, output from the -function, or both. Input parameters are usually values or -const references, while output and input/output -parameters will be pointers to non-const.

    +function, or both. Input parameters should usually be values +or const references, +while required (non-nullable) output and input/output parameters should +usually be references. Generally, use absl::optional to represent +optional inputs, and non-const pointers to represent +optional outputs.

    + +

    +Avoid defining functions that require a const reference parameter +to outlive the call, because const reference parameters bind +to temporaries. Instead, find a way to eliminate the lifetime requirement +(for example, by copying the parameter), or pass it by const +pointer and document the non-null requirement. + +

    When ordering function parameters, put all input-only parameters before any output parameters. In particular, do not add new parameters to the end of the function just because they are new; place new input-only parameters before -the output parameters.

    - -

    This is not a hard-and-fast rule. Parameters that are -both input and output (often classes/structs) muddy the -waters, and, as always, consistency with related -functions may require you to bend the rule.

    +the output parameters. This is not a hard-and-fast rule. Parameters that +are both input and output muddy the waters, and, as always, +consistency with related functions may require you to bend the rule. +Variadic functions may also require unusual parameter ordering.

    Write Short Functions

    @@ -1746,65 +1759,6 @@ errors are hard to debug, or you want to use a piece of it in several different contexts, consider breaking up the function into smaller and more manageable pieces.

    -

    Reference Arguments

    - -

    All parameters passed by lvalue reference must be labeled -const.

    - -

    -

    In C, if a -function needs to modify a variable, the parameter must -use a pointer, eg int foo(int *pval). In -C++, the function can alternatively declare a reference -parameter: int foo(int &val).

    - -

    -

    Defining a parameter as reference avoids ugly code like -(*pval)++. Necessary for some applications -like copy constructors. Makes it clear, unlike with -pointers, that a null pointer is not a possible -value.

    - -

    -

    References can be confusing, as they have value syntax -but pointer semantics.

    - -

    -

    Within function parameter lists all references must be -const:

    - -
    void Foo(const std::string &in, std::string *out);
    -
    - -

    In fact it is a very strong convention in Google code -that input arguments are values or const -references while output arguments are pointers. Input -parameters may be const pointers, but we -never allow non-const reference parameters -except when required by convention, e.g., -swap().

    - -

    However, there are some instances where using -const T* is preferable to const -T& for input parameters. For example:

    - -
      -
    • You want to pass in a null pointer.
    • - -
    • The function saves a pointer or reference to the - input.
    • -
    - -

    Remember that most of the time input -parameters are going to be specified as const -T&. Using const T* instead -communicates to the reader that the input is somehow -treated differently. So if you choose const -T* rather than const T&, do so -for a concrete reason; otherwise it will likely confuse -readers by making them look for an explanation that -doesn't exist.

    -

    Function Overloading

    Use overloaded functions (including constructors) only if a @@ -1993,7 +1947,7 @@ shared, it can be transferred from one piece of code to another.

    "Smart" pointers are classes that act like pointers, -e.g. by overloading the * and +e.g., by overloading the * and -> operators. Some smart pointer types can be used to automate ownership bookkeeping, to ensure these responsibilities are met. @@ -2069,7 +2023,7 @@ all copies, and the object is deleted when the last

  • Shared ownership requires explicit bookkeeping at run-time, which can be costly.
  • -
  • In some cases (e.g. cyclic references), objects +
  • In some cases (e.g., cyclic references), objects with shared ownership may never be deleted.
  • Smart pointers are not perfect substitutes for @@ -2094,7 +2048,7 @@ void FooConsumer(std::unique_ptr<Foo> ptr); without a very good reason. One such reason is to avoid expensive copy operations, but you should only do this if the performance benefits are significant, and the -underlying object is immutable (i.e. +underlying object is immutable (i.e., std::shared_ptr<const Foo>). If you do use shared ownership, prefer to use std::shared_ptr.

    @@ -2131,19 +2085,7 @@ you can download

    Rvalue References

    -

    Use rvalue references to:

    -
      -
    • Define move constructors and move assignment operators.
    • - -
    • Define overload sets with - const& and && variants if you have evidence that this - provides meaningfully better performance than passing by value, - or if you're writing low-overhead generic code that needs to support - arbitrary types. Beware combinatorial overload sets, that is, seldom - overload more than one parameter.
    • - -
    • Support 'perfect forwarding' in generic code.
    • -
    +

    Use rvalue references only in certain special cases listed below.

    Rvalue references @@ -2201,23 +2143,32 @@ rules apply. Such a reference is called forwarding reference.

    -

    You may use rvalue references to define move constructors and move -assignment operators (as described in -Copyable and Movable Types). See the -C++ Primer for more information about -move semantics and std::move.

    +

    Do not use rvalue references (or apply the && +qualifier to methods), except as follows:

    +
      +
    • You may use them to define move constructors and move assignment + operators (as described in + Copyable and Movable Types). +
    • -

      You may use rvalue references to define pairs of overloads, one taking -Foo&& and the other taking const Foo&. -Usually the preferred solution is just to pass by value, but an overloaded pair -of functions sometimes yields better performance and is sometimes necessary in -generic code that needs to support a wide variety of types. As always: if -you're writing more complicated code for the sake of performance, make sure you -have evidence that it actually helps.

      +
    • You may use them to define &&-qualified methods that + logically "consume" *this, leaving it in an unusable + or empty state. Note that this applies only to method qualifiers (which come + after the closing parenthesis of the function signature); if you want to + "consume" an ordinary function parameter, prefer to pass it by value.
    • -

      You may use forwarding references in conjunction with -std::forward, -to support perfect forwarding.

      +
    • You may use forwarding references in conjunction with + std::forward, + to support perfect forwarding.
    • + +
    • You may use them to define pairs of overloads, such as one taking + Foo&& and the other taking const Foo&. + Usually the preferred solution is just to pass by value, but an overloaded + pair of functions sometimes yields better performance and is sometimes + necessary in generic code that needs to support a wide variety of types. + As always: if you're writing more complicated code for the sake of + performance, make sure you have evidence that it actually helps.
    • +

    Friends

    @@ -2373,14 +2324,14 @@ throw any exceptions.

    • Specifying move constructors as noexcept - improves performance in some cases, e.g. + improves performance in some cases, e.g., std::vector<T>::resize() moves rather than copies the objects if T's move constructor is noexcept.
    • Specifying noexcept on a function can trigger compiler optimizations in environments where - exceptions are enabled, e.g. compiler does not have to + exceptions are enabled, e.g., compiler does not have to generate extra code for stack-unwinding, if it knows that no exceptions can be thrown due to a noexcept specifier.
    • @@ -2404,7 +2355,7 @@ throw any exceptions.

      You may use noexcept when it is useful for performance if it accurately reflects the intended semantics -of your function, i.e. that if an exception is somehow thrown +of your function, i.e., that if an exception is somehow thrown from within the function body then it represents a fatal error. You can assume that noexcept on move constructors has a meaningful performance benefit. If you think @@ -2414,19 +2365,19 @@ with your project leads.

      Prefer unconditional noexcept if exceptions are -completely disabled (i.e. most Google C++ environments). +completely disabled (i.e., most Google C++ environments). Otherwise, use conditional noexcept specifiers with simple conditions, in ways that evaluate false only in the few cases where the function could potentially throw. The tests might include type traits check on whether the -involved operation might throw (e.g. +involved operation might throw (e.g., std::is_nothrow_move_constructible for move-constructing objects), or on whether allocation can throw -(e.g. absl::default_allocator_is_nothrow for +(e.g., absl::default_allocator_is_nothrow for standard default allocation). Note in many cases the only possible cause for an exception is allocation failure (we believe move constructors should not throw except due to -allocation failure), and there are many applications where it’s +allocation failure), and there are many applications where it’s appropriate to treat memory exhaustion as a fatal error rather than an exceptional condition that your program should attempt to recover from. Even for other @@ -2434,7 +2385,7 @@ potential failures you should prioritize interface simplicity over supporting all possible exception throwing scenarios: instead of writing a complicated noexcept clause that depends on whether a hash function can throw, for example, -simply document that your component doesn’t support hash +simply document that your component doesn’t support hash functions throwing and make it unconditionally noexcept.

      @@ -2542,9 +2493,9 @@ workarounds disguise your true intent.

      like static_cast<float>(double_value), or brace initialization for conversion of arithmetic types like int64 y = int64{1} << 42. Do not use -cast formats like -int y = (int)x or int y = int(x) (but the latter -is okay when invoking a constructor of a class type).

      +cast formats like (int)x unless the cast is to +void. You may use cast formats like `T(x)` only when +`T` is a class type.

      C++ introduced a @@ -2564,12 +2515,13 @@ them.

      The C++-style cast syntax is verbose and cumbersome.

      -

      Do not use C-style casts. Instead, use these C++-style casts when -explicit type conversion is necessary.

      +

      In general, do not use C-style casts. Instead, use these C++-style +casts when explicit type conversion is necessary. +

      • Use brace initialization to convert arithmetic types - (e.g. int64{x}). This is the safest approach because code + (e.g., int64{x}). This is the safest approach because code will not compile if conversion can result in information loss. The syntax is also concise.
      • @@ -2694,7 +2646,7 @@ localization, and security hardening.

        If you do use streams, avoid the stateful parts of the streams API (other than error state), such as imbue(), xalloc(), and register_callback(). -Use explicit formatting functions (see e.g. +Use explicit formatting functions (see e.g., absl/strings) rather than @@ -2712,9 +2664,8 @@ convention).

        Preincrement and Predecrement

        -

        Use prefix form (++i) of the increment and -decrement operators with iterators and other template -objects.

        +

        Use the prefix form (++i) of the increment +and decrement operators unless you need postfix semantics.

        When a variable @@ -2725,29 +2676,24 @@ whether to preincrement (decrement) or postincrement (decrement).

        -

        When the return value is ignored, the "pre" form -(++i) is never less efficient than the -"post" form (i++), and is often more -efficient. This is because post-increment (or decrement) -requires a copy of i to be made, which is -the value of the expression. If i is an -iterator or other non-scalar type, copying i -could be expensive. Since the two types of increment -behave the same when the value is ignored, why not just -always pre-increment?

        + +

        A postfix increment/decrement expression evaluates to the value +as it was before it was modified. This can result in code that is more +compact but harder to read. The prefix form is generally more readable, is +never less efficient, and can be more efficient because it doesn't need to +make a copy of the value as it was before the operation. +

        -

        The tradition developed, in C, of using post-increment +

        The tradition developed, in C, of using post-increment, even when the expression value is not used, especially in for loops. Some find post-increment easier to read, since the "subject" (i) precedes the "verb" (++), just like in English.

        -

        For simple scalar -(non-object) values there is no reason to prefer one form -and we allow either. For iterators and other template -types, use pre-increment.

        +

        Use prefix increment/decrement, unless the code explicitly +needs the result of the postfix increment/decrement expression.

        Use of const

        @@ -2784,7 +2730,7 @@ functions.

        We strongly recommend using const -in APIs (i.e. on function parameters, methods, and +in APIs (i.e., on function parameters, methods, and non-local variables) wherever it is meaningful and accurate. This provides consistent, mostly compiler-verified documentation of what objects an operation can mutate. Having @@ -2808,7 +2754,7 @@ many other contexts as well. In particular:

      • Declare methods to be const unless they alter the logical state of the object (or enable the user to modify - that state, e.g. by returning a non-const reference, but that's + that state, e.g., by returning a non-const reference, but that's rare), or they can't safely be invoked concurrently.
      @@ -2847,7 +2793,7 @@ constants or to ensure constant initialization.

      Some variables can be declared constexpr -to indicate the variables are true constants, i.e. fixed at +to indicate the variables are true constants, i.e., fixed at compilation/link time. Some functions and constructors can be declared constexpr which enables them to be used in defining a constexpr @@ -3006,7 +2952,7 @@ problems of printing, comparisons, and structure alignment.

      or std::ostream.

      Unfortunately, the PRI macros are the only portable way to - specify a conversion for the standard bitwidth typedefs (e.g. + specify a conversion for the standard bitwidth typedefs (e.g., int64_t, uint64_t, int32_t, uint32_t, etc). @@ -3126,7 +3072,7 @@ possible:

      function/class/variable names.
    -

    Exporting macros from headers (i.e. defining them in a header +

    Exporting macros from headers (i.e., defining them in a header without #undefing them before the end of the header) is extremely strongly discouraged. If you do export a macro from a header, it must have a globally unique name. To achieve this, it @@ -3165,11 +3111,11 @@ to any particular variable, such as code that manages an external or internal data format where a variable of an appropriate C++ type is not convenient.

    -
    struct data;
    +
    MyStruct data;
     memset(&data, 0, sizeof(data));
     
    -
    memset(&data, 0, sizeof(Struct));
    +
    memset(&data, 0, sizeof(MyStruct));
     
    if (raw_size < sizeof(int)) {
    @@ -3227,7 +3173,7 @@ auto d{42};   // d is an int, not a std::initializer_list<int>
         Lambda expression return types can be
         deduced in the same way, but this is triggered by omitting the return type,
         rather than by an explicit auto. Confusingly,
    -    trailing return type syntax for functions
    +    trailing return type syntax for functions
         also uses auto in the return-type position, but that doesn't
         rely on type deduction; it's just an alternate syntax for an explicit
         return type.
    @@ -3237,7 +3183,7 @@ auto d{42};   // d is an int, not a std::initializer_list<int>
         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 auto function parameter:
    -    
    // Sort `vec` in increasing order
    +    
    // Sort `vec` in decreasing order
     std::sort(vec.begin(), vec.end(), [](auto lhs, auto rhs) { return lhs > rhs; });
  • Lambda init captures
    @@ -3268,6 +3214,7 @@ if (!success) { the binding types typically won't be references even if the declaration declares a reference (but they will usually behave like references anyway). +

    (These summaries omit many details and caveats; see the links for further information.)

    @@ -3312,12 +3259,12 @@ auto i = y.Find(key); inconvenience of writing an explicit type. When judging whether the code is clearer, keep in mind that your readers are not necessarily on your team, or familiar with your project, so types that you and - your reviewer experience as as unnecessary clutter will very often + your reviewer experience as unnecessary clutter will very often provide useful information to others. For example, you can assume that the return type of make_unique<Foo>() is obvious, but the return type of MyWidgetFactory() probably isn't.

    -

    These principles applies to all forms of type deduction, but the +

    These principles apply to all forms of type deduction, but the details vary, as described in the following sections.

    Function template argument deduction

    @@ -3339,7 +3286,7 @@ auto i = y.Find(key); absl::flat_hash_map<std::string, std::unique_ptr<WidgetWithBellsAndWhistles>>::const_iterator it = my_map_.find(key); -std::array<int, 0> numbers = {4, 8, 15, 16, 23, 42}; +std::array<int, 6> numbers = {4, 8, 15, 16, 23, 42};
    auto widget_ptr = absl::make_unique<WidgetWithBellsAndWhistles>(arg1, arg2);
     auto it = my_map_.find(key);
    @@ -3386,7 +3333,7 @@ if (it != my_map_.end()) {
       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.
    +  obvious what arguments it will eventually be called with (e.g.,
       the std::sort example above).

    Lambda init captures

    @@ -3476,6 +3423,52 @@ array(T, U...) -> std::array<T, 1 + sizeof...(U)>;

    Uses of CTAD must also follow the general rules on Type deduction.

    +

    Designated initializers

    + +

    Use designated initializers only in their C++20-compliant form.

    + +

    +

    + Designated initializers are a syntax that allows for initializing an + aggregate ("plain old struct") by naming its fields explicitly: +

      struct Point {
    +    float x = 0.0;
    +    float y = 0.0;
    +    float z = 0.0;
    +  };
    +
    +  Point p = {
    +    .x = 1.0,
    +    .y = 2.0,
    +    // z will be 0.0
    +  };
    + The explicitly listed fields will be initialized as specified, and others + will be initialized in the same way they would be in a traditional aggregate + initialization expression like Point{1.0, 2.0}. + +

    +

    Designated initializers can make for convenient and highly readable +aggregate expressions, especially for structs with less straightforward +ordering of fields than the Point example above.

    + +

    +

    While designated initializers have long been part of the C standard and +supported by C++ compilers as an extension, only recently have they made it +into the draft C++ standard. They are on track for publishing in C++20.

    + +

    The rules in the draft C++ standard are stricter than in C and compiler +extensions, requiring that the designated initializers appear in the same order +as the fields appear in the struct definition. So in the example above it is +legal according to draft C++20 to initialize x and then +z, but not y and then x.

    + +

    +

    Use designated initializers only in the form that is compatible with the +draft C++20 standard: with initializers in the same order as the corresponding +fields appear in the struct definition.

    + + +

    Lambda expressions

    Use lambda expressions where appropriate. Prefer explicit captures @@ -3567,7 +3560,7 @@ std::sort(indices.begin(), indices.end(), [&](int a, int b) { initializers), but they look nothing like any other variable declaration syntax in C++. In particular, there's no place for the variable's type, or even an auto placeholder (although init captures can - indicate it indirectly, e.g. with a cast). This can make it difficult to + indicate it indirectly, e.g., with a cast). This can make it difficult to even recognize them as declarations.

  • Init captures inherently rely on type @@ -3857,12 +3850,12 @@ language does not allow us to extend it to support them.

    You can use std::hash with the types that it supports "out of the box", but do not specialize it to support additional types. If you need a hash table with a key type that std::hash -does not support, consider using legacy hash containers (e.g. +does not support, consider using legacy hash containers (e.g., hash_map) for now; they use a different default hasher, which is unaffected by this prohibition.

    If you want to use the standard hash containers anyway, you will -need to specify a custom hasher for the key type, e.g.

    +need to specify a custom hasher for the key type, e.g.,

    std::unordered_map<MyKeyType, Value, MyKeyTypeHasher> my_map;
     

    Consult with the type's owners to see if there is an existing hasher @@ -3879,7 +3872,7 @@ using a new customization mechanism that doesn't have the drawbacks of

    As with Boost, some modern C++ extensions encourage coding practices that hamper -readability—for example by removing +readability—for example by removing checked redundancy (such as type names) that may be helpful to readers, or by encouraging template metaprogramming. Other extensions duplicate functionality @@ -3917,9 +3910,8 @@ guide, the following C++ features may not be used:

    Compilers support various extensions that are not part of standard C++. Such extensions include GCC's __attribute__, intrinsic functions such - as __builtin_prefetch, designated initializers (e.g. - Foo f = {.field = 3}), inline assembly, __COUNTER__, - __PRETTY_FUNCTION__, compound statement expressions (e.g. + as __builtin_prefetch, inline assembly, __COUNTER__, + __PRETTY_FUNCTION__, compound statement expressions (e.g., foo = ({ int x; Bar(&x); x }), variable-length arrays and alloca(), and the "Elvis Operator" a?:b.

    @@ -3927,9 +3919,7 @@ guide, the following C++ features may not be used:

    • Nonstandard extensions may provide useful features that do not exist - in standard C++. For example, some people think that designated - initializers are more readable than standard C++ features like - constructors.
    • + in standard C++.
    • Important performance guidance to the compiler can only be specified using extensions.
    @@ -4023,9 +4013,9 @@ using TimeSeries = std::unordered_set<DataPoint, std::hash<DataPoint>,
    namespace mynamespace {
     // Bad: none of these say how they should be used.
    -using DataPoint = foo::Bar*;
    -using std::unordered_set;  // Bad: just for local convenience
    -using std::hash;           // Bad: just for local convenience
    +using DataPoint = ::foo::Bar*;
    +using ::std::unordered_set;  // Bad: just for local convenience
    +using ::std::hash;           // Bad: just for local convenience
     typedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator> TimeSeries;
     }  // namespace mynamespace
     
    @@ -4034,7 +4024,7 @@ typedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator&g classes, explicitly marked internal namespaces, and in .cc files:

    // In a .cc file
    -using foo::Bar;
    +using ::foo::Bar;
     

    Naming

    @@ -4112,10 +4102,13 @@ but within the scope of a class, it's likely too vague.

    template parameter.

    For the purposes of the naming rules below, a "word" is anything that you -would write in English without internal spaces. This includes abbreviations and -acronyms; e.g., for "camel -case" or "Pascal case," in which the first letter of each word is -capitalized, use a name like StartRpc(), not +would write in English without internal spaces. This includes abbreviations, +such as acronyms and initialisms. For names written in mixed case (also +sometimes referred to as +"camel case" or +"Pascal case"), in +which the first letter of each word is capitalized, prefer to capitalize +abbreviations as single words, e.g., StartRpc() rather than StartRPC().

    Template parameters should follow the naming style for their @@ -4163,8 +4156,8 @@ of files called, e.g., foo_bar.h and letter for each new word, with no underscores: MyExcitingClass, MyExcitingEnum.

    -

    The names of all types — classes, structs, type aliases, -enums, and type template parameters — have the same naming convention. +

    The names of all types — classes, structs, type aliases, +enums, and type template parameters — have the same naming convention. Type names should start with a capital letter and have a capital letter for each new word. No underscores. For example:

    @@ -4180,7 +4173,7 @@ typedef hash_map<UrlTableProperties *, std::string> PropertiesMap; using PropertiesMap = hash_map<UrlTableProperties *, std::string>; // enums -enum UrlTableErrors { ... +enum class UrlTableError { ...
  • Variable Names

    @@ -4244,10 +4237,10 @@ where capitalization cannot be used for separation. For example:

    const int kAndroid8_0_0 = 24; // Android 8.0.0 -

    All such variables with static storage duration (i.e. statics and globals, +

    All such variables with static storage duration (i.e., statics and globals, see Storage Duration for details) should be named this way. This -convention is optional for variables of other storage classes, e.g. automatic +convention is optional for variables of other storage classes, e.g., automatic variables, otherwise the usual variable naming rules apply.

    Function Names

    @@ -4312,25 +4305,20 @@ in frobber.h)

    Enumerator Names

    -

    Enumerators (for both scoped and unscoped enums) should be named either like -constants or like -macros: either kEnumName or +

    Enumerators (for both scoped and unscoped enums) should be named like +constants, not like +macros. That is, use kEnumName not ENUM_NAME.

    -

    Preferably, the individual enumerators should be named -like constants. However, it -is also acceptable to name them like -macros. The enumeration name, -UrlTableErrors (and -AlternateUrlTableErrors), is a type, and -therefore mixed case.

    -
    enum UrlTableErrors {
    +
    +
    enum class UrlTableError {
       kOk = 0,
    -  kErrorOutOfMemory,
    -  kErrorMalformedInput,
    +  kOutOfMemory,
    +  kMalformedInput,
     };
    -enum AlternateUrlTableErrors {
    +
    +
    enum class AlternateUrlTableError {
       OK = 0,
       OUT_OF_MEMORY = 1,
       MALFORMED_INPUT = 2,
    @@ -4341,10 +4329,8 @@ enum AlternateUrlTableErrors {
     like macros. This caused
     problems with name collisions between enum values and
     macros. Hence, the change to prefer constant-style naming
    -was put in place. New code should prefer constant-style
    -naming if possible. However, there is no reason to change
    -old code to use constant-style names, unless the old
    -names are actually causing a compile-time problem.

    +was put in place. New code should use constant-style +naming.

    @@ -4398,7 +4384,7 @@ names that you must then explain through comments.

    When writing your comments, write for your audience: the next contributor who will need to -understand your code. Be generous — the next +understand your code. Be generous — the next one may be you!

    Comment Style

    @@ -4452,8 +4438,9 @@ not at the file level.

    Class Comments

    -

    Every non-obvious class declaration should have an accompanying -comment that describes what it is for and how it should be used.

    +

    Every non-obvious class or struct declaration should have an +accompanying comment that describes what it is for and how it should +be used.

    // Iterates over the contents of a GargantuanTable.
     // Example:
    @@ -4477,7 +4464,7 @@ surrounding multithreaded use.

    The class comment is often a good place for a small example code snippet demonstrating a simple and focused usage of the class.

    -

    When sufficiently separated (e.g. .h and .cc +

    When sufficiently separated (e.g., .h and .cc files), comments describing the use of the class should go together with its interface definition; comments about the class operation and implementation should accompany the implementation of the class's methods.

    @@ -4493,7 +4480,7 @@ operation.

    Almost every function declaration should have comments immediately preceding it that describe what the function does and how to use it. These comments may be omitted only if the function is simple and -obvious (e.g. simple accessors for obvious properties of the +obvious (e.g., simple accessors for obvious properties of the class). These comments should open with descriptive verbs in the indicative mood ("Opens the file") rather than verbs in the imperative ("Open the file"). The comment describes the function; it does not @@ -4653,7 +4640,7 @@ the code is doing, and comments that mention that an error has already been logged when the function returns.

    -

    Function Argument Comments

    +

    Function Argument Comments

    When the meaning of a function argument is nonobvious, consider one of the following remedies:

    @@ -4777,7 +4764,7 @@ name that is given.

    // TODO(kl@gmail.com): Use a "*" here for concatenation operator.
     // TODO(Zeke) change this to use relations.
    -// TODO(bug 12345): remove the "Last visitors" feature
    +// TODO(bug 12345): remove the "Last visitors" feature.
     
    @@ -4846,7 +4833,7 @@ can easily show longer lines.

    • a comment line which is not feasible to split without harming - readability, ease of cut and paste or auto-linking -- e.g. if a line + readability, ease of cut and paste or auto-linking -- e.g., if a line contains an example command or a literal URL longer than 80 characters.
    • a raw-string literal with content that exceeds 80 characters. Except for @@ -4878,7 +4865,7 @@ understood by most tools able to handle more than just ASCII.

      Hex encoding is also OK, and encouraged where it -enhances readability — for example, +enhances readability — for example, "\xEF\xBB\xBF", or, even more simply, u8"\uFEFF", is the Unicode zero-width no-break space character, which would be invisible if @@ -5138,7 +5125,7 @@ my_widget.Transform(x1, x2, x3,

      Format a braced initializer list exactly like you would format a function call in its place.

      -

      If the braced list follows a name (e.g. a type or +

      If the braced list follows a name (e.g., a type or variable name), format as if the {} were the parentheses of a function call with that name. If there is no name, assume a zero-length name.

      @@ -5172,19 +5159,10 @@ MyType m = { // Here, you could also break before {.

      Conditionals

      -

      Prefer no spaces inside parentheses. The if -and else keywords belong on separate lines.

      - -

      There are two acceptable formats for a basic -conditional statement. One includes spaces between the -parentheses and the condition, and one does not.

      - -

      The most common form is without spaces. Either is -fine, but be consistent. If you are modifying a -file, use the format that is already present. If you are -writing new code, use the format that the other files in -that directory or project use. If in doubt and you have -no personal preference, do not add the spaces.

      +

      The if and else keywords belong on separate lines. + There should be a space between the if and the open parenthesis, + and between the close parenthesis and the curly brace (if any), but no space + between the parentheses and the condition.

      if (condition) {  // no spaces inside parentheses
         ...  // 2 space indent.
      @@ -5195,22 +5173,8 @@ no personal preference, do not add the spaces.

      }
      -

      If you prefer you may add spaces inside the -parentheses:

      - -
      if ( condition ) {  // spaces inside parentheses - rare
      -  ...  // 2 space indent.
      -} else {  // The else goes on the same line as the closing brace.
      -  ...
      -}
      -
      - -

      Note that in all cases you must have a space between -the if and the open parenthesis. You must -also have a space between the close parenthesis and the -curly brace, if you're using one.

      -
      if(condition) {   // Bad - space missing after IF.
      +if ( condition ) { // Bad - space between the parentheses and the condition
       if (condition){   // Bad - space missing before {.
       if(condition){    // Doubly bad.
       
      @@ -5446,8 +5410,8 @@ though wrapping all operators at the beginning of the line is also allowed. Feel free to insert extra parentheses judiciously because they can be very helpful in increasing readability when used -appropriately. Also note that you should always use -the punctuation operators, such as +appropriately, but be careful about overuse. Also note that you +should always use the punctuation operators, such as && and ~, rather than the word operators, such as and and compl.

      @@ -5658,13 +5622,6 @@ void foo() { // Correct. No extra indentation within namespace. } // namespace
    -

    When declaring nested namespaces, put each namespace -on its own line.

    - -
    namespace foo {
    -namespace bar {
    -
    -

    Horizontal Whitespace

    Use of horizontal whitespace depends on location. Never put @@ -5784,10 +5741,17 @@ useful:

    well help readability.
  • A blank line before a comment line usually helps - readability — the introduction of a new comment suggests + readability — the introduction of a new comment suggests the start of a new thought, and the blank line makes it clear that the comment goes with the following thing instead of the preceding.
  • + +
  • Blank lines immediately inside a declaration of a namespace or block of + namespaces may help readability by visually separating the load-bearing + content from the (largely non-semantic) organizational wrapper. Especially + when the first declaration inside the namespace(s) is preceded by a comment, + this becomes a special case of the previous rule, helping the comment to + "attach" to the subsequent declaration.
  • Exceptions to the Rules