mirror of
https://github.com/google/styleguide.git
synced 2024-03-22 13:11:43 +08:00
Update C++ style guide for C++17.
This commit is contained in:
parent
c89900f721
commit
967e157a00
454
cppguide.html
454
cppguide.html
|
@ -159,20 +159,19 @@ input.</p>
|
||||||
|
|
||||||
<h2 id="C++_Version">C++ Version</h2>
|
<h2 id="C++_Version">C++ Version</h2>
|
||||||
|
|
||||||
<p>
|
<p>Currently, code should target C++17, i.e., should not use C++2x
|
||||||
Currently, code should target C++11, i.e., should not use C++14 or
|
features. The C++ version targeted by this guide will advance
|
||||||
C++17 features. The C++ version targeted by this guide will advance
|
(aggressively) over time.</p>
|
||||||
(aggressively) over time.</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Code should avoid features that have been removed from
|
|
||||||
the latest language version (currently C++17), as well as the rare
|
|
||||||
cases where code has a different meaning in that latest version.
|
|
||||||
Use of some C++ features is restricted or disallowed. Do not use
|
|
||||||
<a href="#Nonstandard_Extensions">non-standard extensions</a>.</p>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<p>Do not use
|
||||||
|
<a href="#Nonstandard_Extensions">non-standard extensions</a>.</p>
|
||||||
|
|
||||||
|
<div>Consider portability to other environments
|
||||||
|
before using features from C++14 and C++17 in your project.
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2 id="Header_Files">Header Files</h2>
|
<h2 id="Header_Files">Header Files</h2>
|
||||||
|
|
||||||
<p>In general, every <code>.cc</code> file should have an
|
<p>In general, every <code>.cc</code> file should have an
|
||||||
|
@ -1914,7 +1913,7 @@ doubt, use overloads.</p>
|
||||||
form, the return type appears before the function name. For example:</p>
|
form, the return type appears before the function name. For example:</p>
|
||||||
<pre>int foo(int x);
|
<pre>int foo(int x);
|
||||||
</pre>
|
</pre>
|
||||||
<p>The new form, introduced in C++11, uses the <code>auto</code>
|
<p>The newer form, introduced in C++11, uses the <code>auto</code>
|
||||||
keyword before the function name and a trailing return type after
|
keyword before the function name and a trailing return type after
|
||||||
the argument list. For example, the declaration above could
|
the argument list. For example, the declaration above could
|
||||||
equivalently be written:</p>
|
equivalently be written:</p>
|
||||||
|
@ -2752,7 +2751,7 @@ types, use pre-increment.</p>
|
||||||
|
|
||||||
<h3 id="Use_of_const">Use of const</h3>
|
<h3 id="Use_of_const">Use of const</h3>
|
||||||
|
|
||||||
<p>In APIs, use <code>const</code> whenever it makes sense. With C++11,
|
<p>In APIs, use <code>const</code> whenever it makes sense.
|
||||||
<code>constexpr</code> is a better choice for some uses of
|
<code>constexpr</code> is a better choice for some uses of
|
||||||
const.</p>
|
const.</p>
|
||||||
|
|
||||||
|
@ -2843,7 +2842,7 @@ consistent with the code around you!</p>
|
||||||
|
|
||||||
<h3 id="Use_of_constexpr">Use of constexpr</h3>
|
<h3 id="Use_of_constexpr">Use of constexpr</h3>
|
||||||
|
|
||||||
<p>In C++11, use <code>constexpr</code> to define true
|
<p>Use <code>constexpr</code> to define true
|
||||||
constants or to ensure constant initialization.</p>
|
constants or to ensure constant initialization.</p>
|
||||||
|
|
||||||
<p class="definition"></p>
|
<p class="definition"></p>
|
||||||
|
@ -3166,7 +3165,7 @@ to any particular variable, such as code that manages an
|
||||||
external or internal data format where a variable of an
|
external or internal data format where a variable of an
|
||||||
appropriate C++ type is not convenient.</p>
|
appropriate C++ type is not convenient.</p>
|
||||||
|
|
||||||
<pre>Struct data;
|
<pre>struct data;
|
||||||
memset(&data, 0, sizeof(data));
|
memset(&data, 0, sizeof(data));
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
@ -3179,89 +3178,303 @@ memset(&data, 0, sizeof(data));
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<h3 id="auto">auto</h3>
|
<a name="auto"></a>
|
||||||
|
<h3 id="Type_deduction">Type deduction</h3>
|
||||||
|
|
||||||
<p>Use <code>auto</code> to avoid type names that are noisy, obvious,
|
<p>Use type deduction only if it makes the code clearer to readers who aren't
|
||||||
or unimportant - cases where the type doesn't aid in clarity for the
|
familiar with the project, or if it makes the code safer. Do not use it
|
||||||
reader. Continue to use manifest type declarations when it helps
|
merely to avoid the inconvenience of writing an explicit type.</p>
|
||||||
readability.</p>
|
|
||||||
|
<p class="definition"></p>
|
||||||
|
|
||||||
|
<p>There are several contexts in which C++ allows (or even requires) types to
|
||||||
|
be deduced by the compiler, rather than spelled out explicitly in the code:</p>
|
||||||
|
<dl>
|
||||||
|
<dt><a href="https://en.cppreference.com/w/cpp/language/template_argument_deduction">Function template argument deduction</a></dt>
|
||||||
|
<dd>A function template can be invoked without explicit template arguments.
|
||||||
|
The compiler deduces those arguments from the types of the function
|
||||||
|
arguments:
|
||||||
|
<pre class="neutralcode">template <typename T>
|
||||||
|
void f(T t);
|
||||||
|
|
||||||
|
f(0); // Invokes f<int>(0)</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
|
||||||
|
of the type. The compiler deduces the type from the variable's
|
||||||
|
initializer, following the same rules as function template argument
|
||||||
|
deduction with the same initializer (so long as you don't use curly braces
|
||||||
|
instead of parentheses).
|
||||||
|
<pre class="neutralcode">auto a = 42; // a is an int
|
||||||
|
auto& b = a; // b is an int&
|
||||||
|
auto c = b; // c is an int
|
||||||
|
auto d{42}; // d is an int, not a std::initializer_list<int>
|
||||||
|
</pre>
|
||||||
|
<code>auto</code> can be qualified with <code>const</code>, and can be
|
||||||
|
used as part of a pointer or reference type, but it can't be used as a
|
||||||
|
template argument. A rare variant of this syntax uses
|
||||||
|
<code>decltype(auto)</code> instead of <code>auto</code>, in which case
|
||||||
|
the deduced type is the result of applying
|
||||||
|
<a href="https://en.cppreference.com/w/cpp/language/decltype"><code>decltype</code></a>
|
||||||
|
to the initializer.
|
||||||
|
</dd>
|
||||||
|
<dt><a href="https://en.cppreference.com/w/cpp/language/function#Return_type_deduction">Function return type deduction</a></dt>
|
||||||
|
<dd><code>auto</code> (and <code>decltype(auto)</code>) can also be used in
|
||||||
|
place of a function return type. The compiler deduces the return type from
|
||||||
|
the <code>return</code> statements in the function body, following the same
|
||||||
|
rules as for variable declarations:
|
||||||
|
<pre class="neutralcode">auto f() { return 0; } // The return type of f is int</pre>
|
||||||
|
<a href="#Lambda_expressions">Lambda expression</a> return types can be
|
||||||
|
deduced in the same way, but this is triggered by omitting the return type,
|
||||||
|
rather than by an explicit <code>auto</code>. Confusingly,
|
||||||
|
<a href="trailing_return">trailing return type</a> syntax for functions
|
||||||
|
also uses <code>auto</code> in the return-type position, but that doesn't
|
||||||
|
rely on type deduction; it's just an alternate 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:
|
||||||
|
<pre class="neutralcode">// Sort `vec` in increasing order
|
||||||
|
std::sort(vec.begin(), vec.end(), [](auto lhs, auto rhs) { return lhs > rhs; });</pre>
|
||||||
|
</dd>
|
||||||
|
<dt><a href="https://isocpp.org/wiki/faq/cpp14-language#lambda-captures">Lambda init captures</a></dt>
|
||||||
|
<dd>Lambda captures can have explicit initializers, which can be used to
|
||||||
|
declare wholly new variables rather than only capturing existing ones:
|
||||||
|
<pre class="neutralcode">[x = 42, y = "foo"] { ... } // x is an int, and y is a const char*</pre>
|
||||||
|
This syntax doesn't allow the type to be specified; instead, it's deduced
|
||||||
|
using the rules for <code>auto</code> variables.
|
||||||
|
</dd>
|
||||||
|
<dt><a href="https://en.cppreference.com/w/cpp/language/class_template_argument_deduction">Class template argument deduction</a></dt>
|
||||||
|
<dd>See <a href="#CTAD">below</a>.</dd>
|
||||||
|
<dt><a href="https://en.cppreference.com/w/cpp/language/structured_binding">Structured bindings</a></dt>
|
||||||
|
<dd>When declaring a tuple, struct, or array using <code>auto</code>, you can
|
||||||
|
specify names for the individual elements instead of a name for the whole
|
||||||
|
object; these names are called "structured bindings", and the whole
|
||||||
|
declaration is called a "structured binding declaration". This syntax
|
||||||
|
provides no way of specifying the type of either the enclosing object
|
||||||
|
or the individual names:
|
||||||
|
<pre class="neutralcode">auto [iter, success] = my_map.insert({key, value});
|
||||||
|
if (!success) {
|
||||||
|
iter->second = value;
|
||||||
|
}</pre>
|
||||||
|
The <code>auto</code> can also be qualified with <code>const</code>,
|
||||||
|
<code>&</code>, and <code>&&</code>, but note that these qualifiers
|
||||||
|
technically apply to the anonymous tuple/struct/array, rather than the
|
||||||
|
individual bindings. The rules that determine the types of the bindings
|
||||||
|
are quite complex; the results tend to be unsurprising, except that
|
||||||
|
the binding types typically won't be references even if the declaration
|
||||||
|
declares a reference (but they will usually behave like references anyway).
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<p>(These summaries omit many details and caveats; see the links for further
|
||||||
|
information.)</p>
|
||||||
|
|
||||||
<p class="pros"></p>
|
<p class="pros"></p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>C++ type names can be long and cumbersome, especially when they
|
<li>C++ type names can be long and cumbersome, especially when they
|
||||||
involve templates or namespaces.</li>
|
involve templates or namespaces.</li>
|
||||||
<li>When a C++ type name is repeated within a single declaration or a
|
<li>When a C++ type name is repeated within a single declaration or a
|
||||||
small code region, the repetition may not be aiding readability.</li>
|
small code region, the repetition may not be aiding readability.</li>
|
||||||
<li>It is sometimes safer to let the type be specified by the type of
|
<li>It is sometimes safer to let the type be deduced, since that avoids
|
||||||
the initialization expression, since that avoids the possibility of
|
the possibility of unintended copies or type conversions.</li>
|
||||||
unintended copies or type conversions.</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p class="cons"></p>
|
<p class="cons"></p>
|
||||||
<p>Sometimes code is clearer when types are manifest,
|
<p>C++ code is usually clearer when types are explicit,
|
||||||
especially when a variable's initialization depends on
|
especially when type deduction would depend on information from
|
||||||
things that were declared far away. In expressions
|
distant parts of the code. In expressions like:</p>
|
||||||
like:</p>
|
|
||||||
|
|
||||||
<pre class="badcode">auto foo = x.add_foo();
|
<pre class="badcode">auto foo = x.add_foo();
|
||||||
auto i = y.Find(key);
|
auto i = y.Find(key);
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>it may not be obvious what the resulting types are if the type
|
<p>it may not be obvious what the resulting types are if the type
|
||||||
of <code>y</code> isn't very well known, or if <code>y</code> was
|
of <code>y</code> isn't very well known, or if <code>y</code> was
|
||||||
declared many lines earlier.</p>
|
declared many lines earlier.</p>
|
||||||
|
|
||||||
<p>Programmers have to understand the difference between
|
<p>Programmers have to understand when type deduction will or won't
|
||||||
<code>auto</code> and <code>const auto&</code> or
|
produce a reference type, or they'll get copies when they didn't
|
||||||
they'll get copies when they didn't mean to.</p>
|
mean to.</p>
|
||||||
|
|
||||||
<p>If an <code>auto</code> variable is used as part of an
|
<p>If a deduced type is used as part of an interface, then a
|
||||||
interface, e.g. as a constant in a header, then a
|
programmer might change its type while only intending to
|
||||||
programmer might change its type while only intending to
|
change its value, leading to a more radical API change
|
||||||
change its value, leading to a more radical API change
|
than intended.</p>
|
||||||
than intended.</p>
|
|
||||||
|
|
||||||
<p class="decision"></p>
|
<p class="decision"></p>
|
||||||
<p><code>auto</code> is permitted when it increases readability,
|
|
||||||
particularly as described below. Never initialize an <code>auto</code>-typed
|
|
||||||
variable with a braced initializer list.</p>
|
|
||||||
|
|
||||||
<p>Specific cases where <code>auto</code> is allowed or encouraged:
|
<p>The fundamental rule is: use type deduction only to make the code
|
||||||
</p><ul>
|
clearer or safer, and do not use it merely to avoid the
|
||||||
<li>(Encouraged) For iterators and other long/cluttery type names, particularly
|
inconvenience of writing an explicit type. When judging whether the
|
||||||
when the type is clear from context (calls
|
code is clearer, keep in mind that your readers are not necessarily
|
||||||
to <code>find</code>, <code>begin</code>, or <code>end</code> for
|
on your team, or familiar with your project, so types that you and
|
||||||
instance).</li>
|
your reviewer experience as as unnecessary clutter will very often
|
||||||
<li>(Allowed) When the type is clear from local context (in the same expression
|
provide useful information to others. For example, you can assume that
|
||||||
or within a few lines). Initialization of a pointer or smart pointer
|
the return type of <code>make_unique<Foo>()</code> is obvious,
|
||||||
with calls
|
but the return type of <code>MyWidgetFactory()</code> probably isn't.</p>
|
||||||
to <code>new</code> and
|
|
||||||
<code>std::make_unique</code>
|
|
||||||
commonly falls into this category, as does use of <code>auto</code> in
|
|
||||||
a range-based loop over a container whose type is spelled out
|
|
||||||
nearby.</li>
|
|
||||||
<li>(Allowed) When the type doesn't matter because it isn't being used for
|
|
||||||
anything other than equality comparison.</li>
|
|
||||||
<li>(Encouraged) When iterating over a map with a range-based loop
|
|
||||||
(because it is often assumed that the correct type
|
|
||||||
is <code>std::pair<KeyType, ValueType></code> whereas it is actually
|
|
||||||
<code>std::pair<const KeyType, ValueType></code>). This is
|
|
||||||
particularly well paired with local <code>key</code>
|
|
||||||
and <code>value</code> aliases for <code>.first</code>
|
|
||||||
and <code>.second</code> (often const-ref).
|
|
||||||
<pre>for (const auto& item : some_map) {
|
|
||||||
const KeyType& key = item.first;
|
|
||||||
const ValType& value = item.second;
|
|
||||||
// The rest of the loop can now just refer to key and value,
|
|
||||||
// a reader can see the types in question, and we've avoided
|
|
||||||
// the too-common case of extra copies in this iteration.
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
<p>These principles applies to all forms of type deduction, but the
|
||||||
|
details vary, as described in the following sections.</p>
|
||||||
|
|
||||||
|
<h4>Function template argument deduction</h4>
|
||||||
|
|
||||||
|
<p>Function template argument deduction is almost always OK. Type deduction
|
||||||
|
is the expected default way of interacting with function templates,
|
||||||
|
because it allows function templates to act like infinite sets of ordinary
|
||||||
|
function overloads. Consequently, function templates are almost always
|
||||||
|
designed so that template argument deduction is clear and safe, or
|
||||||
|
doesn't compile.</p>
|
||||||
|
|
||||||
|
<h4>Local variable type deduction</h4>
|
||||||
|
|
||||||
|
<p>For local variables, you can use type deduction to make the code clearer
|
||||||
|
by eliminating type information that is obvious or irrelevant, so that
|
||||||
|
the reader can focus on the meaningful parts of the code:
|
||||||
|
</p><pre class="neutralcode">std::unique_ptr<WidgetWithBellsAndWhistles> widget_ptr =
|
||||||
|
absl::make_unique<WidgetWithBellsAndWhistles>(arg1, arg2);
|
||||||
|
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};</pre>
|
||||||
|
|
||||||
|
<pre class="goodcode">auto widget_ptr = absl::make_unique<WidgetWithBellsAndWhistles>(arg1, arg2);
|
||||||
|
auto it = my_map_.find(key);
|
||||||
|
std::array numbers = {4, 8, 15, 16, 23, 42};</pre>
|
||||||
|
|
||||||
|
<p>Types sometimes contain a mixture of useful information and boilerplate,
|
||||||
|
such as <code>it</code> in the example above: it's obvious that the
|
||||||
|
type is an iterator, and in many contexts the container type and even the
|
||||||
|
key type aren't relevant, but the type of the values is probably useful.
|
||||||
|
In such situations, it's often possible to define local variables with
|
||||||
|
explicit types that convey the relevant information:
|
||||||
|
</p><pre class="goodcode">auto it = my_map_.find(key);
|
||||||
|
if (it != my_map_.end()) {
|
||||||
|
WidgetWithBellsAndWhistles& widget = *it->second;
|
||||||
|
// Do stuff with `widget`
|
||||||
|
}</pre>
|
||||||
|
If the type is a template instance, and the parameters are
|
||||||
|
boilerplate but the template itself is informative, you can use
|
||||||
|
class template argument deduction to suppress the boilerplate. However,
|
||||||
|
cases where this actually provides a meaningful benefit are quite rare.
|
||||||
|
Note that class template argument deduction is also subject to a
|
||||||
|
<a href="#CTAD">separate style rule</a>.
|
||||||
|
|
||||||
|
<p>Do not use <code>decltype(auto)</code> if a simpler option will work,
|
||||||
|
because it's a fairly obscure feature, so it has a high cost in code
|
||||||
|
clarity.</p>
|
||||||
|
|
||||||
|
<h4>Return type deduction</h4>
|
||||||
|
|
||||||
|
<p>Use return type deduction (for both functions and lambdas) only if the
|
||||||
|
function body has a very small number of <code>return</code> statements,
|
||||||
|
and very little other code, because otherwise the reader may not be able
|
||||||
|
to tell at a glance what the return type is. Furthermore, use it only
|
||||||
|
if the function or lambda has a very narrow scope, because functions with
|
||||||
|
deduced return types don't define abstraction boundaries: the implementation
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<h4>Lambda init captures</h4>
|
||||||
|
|
||||||
|
<p>Init captures are covered by a <a href="#Lambda_expressions">more specific
|
||||||
|
style rule</a>, which largely supersedes the general rules for
|
||||||
|
type deduction.</p>
|
||||||
|
|
||||||
|
<h4>Structured bindings</h4>
|
||||||
|
|
||||||
|
<p>Unlike other forms of type deduction, structured bindings can actually
|
||||||
|
give the reader additional information, by giving meaningful names to the
|
||||||
|
elements of a larger object. This means that a structured binding declaration
|
||||||
|
may provide a net readability improvement over an explicit type, even in cases
|
||||||
|
where <code>auto</code> would not. Structured bindings are especially
|
||||||
|
beneficial when the object is a pair or tuple (as in the <code>insert</code>
|
||||||
|
example above), because they don't have meaningful field names to begin with,
|
||||||
|
but note that you generally <a href="#Structs_vs._Tuples">shouldn't use
|
||||||
|
pairs or tuples</a> unless a pre-existing API like <code>insert</code>
|
||||||
|
forces you to.</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
|
||||||
|
field names. We recommend using a comment to indicate the name of the
|
||||||
|
underlying field, if it doesn't match the name of the binding, using the
|
||||||
|
same syntax as for function parameter comments:
|
||||||
|
</p><pre>auto [/*field_name1=*/ bound_name1, /*field_name2=*/ bound_name2] = ...</pre>
|
||||||
|
As with function parameter comments, this can enable tools to detect if
|
||||||
|
you get the order of the fields wrong.
|
||||||
|
|
||||||
|
<h3 id="CTAD">Class template argument deduction</h3>
|
||||||
|
|
||||||
|
<p>Use class template argument deduction only with templates that have
|
||||||
|
explicitly opted into supporting it.</p>
|
||||||
|
|
||||||
|
<p class="definition"></p>
|
||||||
|
<p><a href="https://en.cppreference.com/w/cpp/language/class_template_argument_deduction">Class
|
||||||
|
template argument deduction</a> (often abbreviated "CTAD") occurs when
|
||||||
|
a variable is declared with a type that names a template, and the template
|
||||||
|
argument list is not provided (not even empty angle brackets):
|
||||||
|
</p><pre class="neutralcode">std::array a = {1, 2, 3}; // `a` is a std::array<int, 3></pre>
|
||||||
|
The compiler deduces the arguments from the initializer using the
|
||||||
|
template's "deduction guides", which can be explicit or implicit.
|
||||||
|
|
||||||
|
<p>Explicit deduction guides look like function declarations with trailing
|
||||||
|
return types, except that there's no leading <code>auto</code>, and the
|
||||||
|
function name is the name of the template. For example, the above example
|
||||||
|
relies on this deduction guide for <code>std::array</code>:
|
||||||
|
</p><pre class="neutralcode">namespace std {
|
||||||
|
template <class T, class... U>
|
||||||
|
array(T, U...) -> std::array<T, 1 + sizeof...(U)>;
|
||||||
|
}</pre>
|
||||||
|
Constructors in a primary template (as opposed to a template specialization)
|
||||||
|
also implicitly define deduction guides.
|
||||||
|
|
||||||
|
<p>When you declare a variable that relies on CTAD, the compiler selects
|
||||||
|
a deduction guide using the rules of constructor overload resolution,
|
||||||
|
and that guide's return type becomes the type of the variable.</p>
|
||||||
|
|
||||||
|
<p class="pros"></p>
|
||||||
|
<p>CTAD can sometimes allow you to omit boilerplate from your code.</p>
|
||||||
|
|
||||||
|
<p class="cons"></p>
|
||||||
|
<p>The implicit deduction guides that are generated from constructors
|
||||||
|
may have undesirable behavior, or be outright incorrect. This is
|
||||||
|
particularly problematic for constructors written before CTAD was
|
||||||
|
introduced in C++17, because the authors of those constructors had no
|
||||||
|
way of knowing about (much less fixing) any problems that their
|
||||||
|
constructors would cause for CTAD. Furthermore, adding explicit deduction
|
||||||
|
guides to fix those problems might break any existing code that relies on
|
||||||
|
the implicit deduction guides.</p>
|
||||||
|
|
||||||
|
<p>CTAD also suffers from many of the same drawbacks as <code>auto</code>,
|
||||||
|
because they are both mechanisms for deducing all or part of a variable's
|
||||||
|
type from its initializer. CTAD does give the reader more information
|
||||||
|
than <code>auto</code>, but it also doesn't give the reader an obvious
|
||||||
|
cue that information has been omitted.</p>
|
||||||
|
|
||||||
|
<p class="decision"></p>
|
||||||
|
<p>Do not use CTAD with a given template unless the template's maintainers
|
||||||
|
have opted into supporting use of CTAD by providing at least one explicit
|
||||||
|
deduction guide (all templates in the <code>std</code> namespace are
|
||||||
|
also presumed to have opted in). This should be enforced with a compiler
|
||||||
|
warning if available.</p>
|
||||||
|
|
||||||
|
<p>Uses of CTAD must also follow the general rules on
|
||||||
|
<a href="#Type_deduction">Type deduction</a>.</p>
|
||||||
|
|
||||||
<h3 id="Lambda_expressions">Lambda expressions</h3>
|
<h3 id="Lambda_expressions">Lambda expressions</h3>
|
||||||
|
|
||||||
|
@ -3292,8 +3505,8 @@ std::for_each(v.begin(), v.end(), [weight, &sum](int x) {
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Default captures implicitly capture any variable referenced in the
|
<p>Default captures implicitly capture any variable referenced in the
|
||||||
lambda body, including <code>this</code> if any members are used:
|
lambda body, including <code>this</code> if any members are used:</p>
|
||||||
|
|
||||||
<pre>const std::vector<int> lookup_table = ...;
|
<pre>const std::vector<int> lookup_table = ...;
|
||||||
std::vector<int> indices = ...;
|
std::vector<int> indices = ...;
|
||||||
|
@ -3304,10 +3517,22 @@ std::sort(indices.begin(), indices.end(), [&](int a, int b) {
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>Lambdas were introduced in C++11 along with a set of utilities
|
<p>A variable capture can also have an explicit initializer, which can
|
||||||
for working with function objects, such as the polymorphic
|
be used for capturing move-only variables by value, or for other situations
|
||||||
wrapper <code>std::function</code>.
|
not handled by ordinary reference or value captures:
|
||||||
</p>
|
</p><pre>std::unique_ptr<Foo> foo = ...;
|
||||||
|
[foo = std::move(foo)] () {
|
||||||
|
...
|
||||||
|
}</pre>
|
||||||
|
Such captures (often called "init captures" or "generalized lambda captures")
|
||||||
|
need not actually "capture" anything from the enclosing scope, or even have
|
||||||
|
a name from the enclosing scope; this syntax is a fully general way to define
|
||||||
|
members of a lambda object:
|
||||||
|
<pre class="neutralcode">[foo = std::vector<int>({1, 2, 3})] () {
|
||||||
|
...
|
||||||
|
}</pre>
|
||||||
|
The type of a capture with an initializer is deduced using the same rules
|
||||||
|
as <code>auto</code>.
|
||||||
|
|
||||||
<p class="pros"></p>
|
<p class="pros"></p>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -3338,6 +3563,18 @@ wrapper <code>std::function</code>.
|
||||||
This is especially confusing when capturing 'this' by value, since the use
|
This is especially confusing when capturing 'this' by value, since the use
|
||||||
of 'this' is often implicit.</li>
|
of 'this' is often implicit.</li>
|
||||||
|
|
||||||
|
<li>Captures actually declare new variables (whether or not the captures have
|
||||||
|
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 <code>auto</code> placeholder (although init captures can
|
||||||
|
indicate it indirectly, e.g. with a cast). This can make it difficult to
|
||||||
|
even recognize them as declarations.</li>
|
||||||
|
|
||||||
|
<li>Init captures inherently rely on <a href="#Type_deduction">type
|
||||||
|
deduction</a>, and suffer from many of the same drawbacks as
|
||||||
|
<code>auto</code>, with the additional problem that the syntax doesn't
|
||||||
|
even cue the reader that deduction is taking place.</li>
|
||||||
|
|
||||||
<li>It's possible for use of lambdas to get out of
|
<li>It's possible for use of lambdas to get out of
|
||||||
hand; very long nested anonymous functions can make
|
hand; very long nested anonymous functions can make
|
||||||
code harder to understand.</li>
|
code harder to understand.</li>
|
||||||
|
@ -3383,9 +3620,13 @@ few variables for a short lambda, where the set of captured
|
||||||
variables is obvious at a glance. Prefer not to write long or
|
variables is obvious at a glance. Prefer not to write long or
|
||||||
complex lambdas with default capture by value.
|
complex lambdas with default capture by value.
|
||||||
</li>
|
</li>
|
||||||
<li>Specify the return type of the lambda explicitly if that will
|
<li>Use captures only to actually capture variables from the enclosing scope.
|
||||||
make it more obvious to readers, as with
|
Do not use captures with initializers to introduce new names, or
|
||||||
<a href="#auto"><code>auto</code></a>.</li>
|
to substantially change the meaning of an existing name. Instead,
|
||||||
|
declare a new variable in the conventional way and then capture it,
|
||||||
|
or avoid the lambda shorthand and define a function object explicitly.</li>
|
||||||
|
<li>See the section on <a href="#Type_deduction">type deduction</a>
|
||||||
|
for guidance on specifying the parameter and return types.</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -3632,36 +3873,11 @@ that you can use; otherwise work with them to provide one,
|
||||||
using a new customization mechanism that doesn't have the drawbacks of
|
using a new customization mechanism that doesn't have the drawbacks of
|
||||||
<code>std::hash</code>.</p>
|
<code>std::hash</code>.</p>
|
||||||
|
|
||||||
<h3 id="C++11">C++11</h3>
|
|
||||||
|
|
||||||
<p>Use libraries and language extensions from C++11 when appropriate.
|
|
||||||
Consider portability to other environments
|
|
||||||
before using C++11 features in your
|
|
||||||
project. </p>
|
|
||||||
|
|
||||||
<p class="definition"></p>
|
<h3 id="Other_Features"><a name="C++11">Other C++ Features</a></h3>
|
||||||
<p> C++11 contains <a href="https://en.wikipedia.org/wiki/C%2B%2B11">
|
|
||||||
significant changes</a> both to the language and
|
|
||||||
libraries. </p>
|
|
||||||
|
|
||||||
<p class="pros"></p>
|
<p>As with <a href="#Boost">Boost</a>, some modern C++
|
||||||
<p>C++11 was the official standard until 2014, and
|
|
||||||
is supported by most C++ compilers. It standardizes
|
|
||||||
some common C++ extensions that we use already, allows
|
|
||||||
shorthands for some operations, and has some performance
|
|
||||||
and safety improvements.</p>
|
|
||||||
|
|
||||||
<p class="cons"></p>
|
|
||||||
<p>The C++11 standard is substantially more complex than
|
|
||||||
its predecessor (1,300 pages versus 800 pages), and is
|
|
||||||
unfamiliar to many developers. The long-term effects of
|
|
||||||
some features on code readability and maintenance are
|
|
||||||
unknown. We cannot predict when its various features will
|
|
||||||
be implemented uniformly by tools that may be of
|
|
||||||
interest, particularly in the case of projects that are
|
|
||||||
forced to use older versions of tools.</p>
|
|
||||||
|
|
||||||
<p>As with <a href="#Boost">Boost</a>, some C++11
|
|
||||||
extensions encourage coding practices that hamper
|
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
|
checked redundancy (such as type names) that may be
|
||||||
|
@ -3670,12 +3886,9 @@ metaprogramming. Other extensions duplicate functionality
|
||||||
available through existing mechanisms, which may lead to confusion
|
available through existing mechanisms, which may lead to confusion
|
||||||
and conversion costs.</p>
|
and conversion costs.</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<p class="decision"></p>
|
<p class="decision"></p>
|
||||||
<p>C++11 features may be used unless specified otherwise.
|
<p>In addition to what's described in the rest of the style
|
||||||
In addition to what's described in the rest of the style
|
guide, the following C++ features may not be used:</p>
|
||||||
guide, the following C++11 features may not be used:</p>
|
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
|
@ -3689,6 +3902,11 @@ guide, the following C++11 features may not be used:</p>
|
||||||
<code><fenv.h></code> headers, because many
|
<code><fenv.h></code> headers, because many
|
||||||
compilers do not support those features reliably.</li>
|
compilers do not support those features reliably.</li>
|
||||||
|
|
||||||
|
<li>The <code><filesystem></code> header, which
|
||||||
|
|
||||||
|
does not have sufficient support for testing, and suffers
|
||||||
|
from inherent security vulnerabilities.</li>
|
||||||
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user