Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
C
coding-rules
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Container registry
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Scott Snyder
coding-rules
Commits
c99c922f
Commit
c99c922f
authored
1 year ago
by
scott snyder
Browse files
Options
Downloads
Patches
Plain Diff
more c++20 updates
parent
c3c186a8
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
rules.org
+120
-8
120 additions, 8 deletions
rules.org
with
120 additions
and
8 deletions
rules.org
+
120
−
8
View file @
c99c922f
...
...
@@ -763,7 +763,7 @@ for (auto cell : caloCellContainer) ...
auto foo = Foo {x};
#+END_EXAMPLE
There are
three
sorts of places where it generally makes sense to
There are
a few
sorts of places where it generally makes sense to
use =auto=.
- When the type is already evident in the expression and the declaration
...
...
@@ -785,10 +785,38 @@ auto ufoo = std::make_unique<Foo>();
std::map<int, std::string> m = ..;
auto ret = m.insert (std::make_pair (1, "x"));
if (ret.second) ....
#+END_EXAMPLE
- In the case where a class method returns a type defined within the
class, using the =auto= syntax to write the return type at the
end of the signature can make things more readable when the method
is defined out-of-line:
#+BEGIN_EXAMPLE
template <class T> class C {
public:
using ret_t = int;
ret_t foo();
};
// Verbose: the return type is interpreted at the global scope, so it
// needs to be qualified with the class name.
template <class T>
typename C<T>::ret_t C<T>::foo() ...
// With this syntax, the return type is interpreted within the class scope.
template <class T>
auto C<T>::foo() -> ret_t ...
#+END_EXAMPLE
- =auto= may also be useful in writing generic template code.
In some cases, C++20 allows declaring a template function without
the =template= keyword when the argument is declared as =auto=:
#+BEGIN_EXAMPLE
auto fn (auto x) { return x + 1; }
#+END_EXAMPLE
It is recommended to avoid this syntax for public interfaces.
In general, the decision as to whether or not to use =auto= should
be made on the basis of what makes the code easier to _read_.
It is bad practice to use it simply to save a few characters
...
...
@@ -1998,7 +2026,58 @@ private:
that must be acquired in both =getSize()= and =push()= in the above
example.
** Formatted output
- *Prefer std::format to printf or iostream formatting.* [<<use-format>>]
For new code, use the C++20 formatting library to format values to
a string rather than using printf-style formatting or using
iostream manipulators.
Example:
#+BEGIN_EXAMPLE
#include <format>
...
const char* typ = "ele";
float energy = 14.2345;
int mask = 323;
std::cout << std::format ("A {1:.2f} GeV {0} mask {2:#06x}.\n",
typ, energy, mask);
// prints: A 14.23 GeV ele mask 0x0143.
#+END_EXAMPLE
Compare using =printf=-style formatting:
#+BEGIN_EXAMPLE
#include "CxxUtils/StrFormat.h"
...
std::cout << CxxUtils::strformat ("A %.2f GeV %s mask %#06x.\n",
energy, typ, mask);
#+END_EXAMPLE
or =iostream=:
#+BEGIN_EXAMPLE
#include <iomanip>
...
const int default_precision = std::cout.precision();
const std::ios_base::fmtflags default_flags = std::cout.flags();
const char default_fill = std::cout.fill();
std::cout << "A " << std::fixed << std::setprecision(2) << energy
<< std::defaultfloat << std::setprecision(default_precision)
<< " GeV " << typ << " mask "
<< std::hex << "0x" << std::setfill('0') << std::setw(4) << mask
<< std::setfill(default_fill)
<< ".\n";
std::cout.flags(default_flags);
#+END_EXAMPLE
Like the streaming operator, =std::format= has a way of customizing how
a given type is formatted. However, it is somewhat more involved than
for =operator<<=; in addition, =std::format= will not use existing
custom streaming operators. Therefore, for generating printable
representations of class instances, it is probably better in most cases
to use the =iostream= mechanism.
** Assertions and error conditions
- *Pre-conditions and post-conditions should be checked for validity.* [<<pre-post-conditions>>]
...
...
@@ -2208,11 +2287,44 @@ Exception: Mine!
** Parts of C++ to avoid
Here a set of different items are collected. They highlight parts of
the language which should be avoided, because there are better ways to
achieve the desired results. In particular, programmers should avoid
the language which should be avoided, either because there are better ways to
achieve the desired results or because the language features are still
immature. In particular, programmers should avoid
using the old standard C functions, where C++ has introduced new and
safer possibilities.
- *Do not use C++ modules.* [<<no-modules>>]
Modules were introduced in C++20 as a better alternative to =#include=.
If a module is referenced via =import=, it avoids repeatedly parsing
the code as well as avoiding issues that arise due to interference
between headers. However, building modules requires significant
support from the build system, and the support in compilers and
associated tools is still very immature. Even using the standard
library as a module is not fully functional with C++20.
For now, avoid any use of modules. With C++23, it may be possible
to use standard libraries as modules, but building ATLAS code
as modules will require significant additional development.
- *Do not use C++ coroutines.* [<<no-coroutines>>]
Coroutines allow for a non-linear style of control flow, where one
can return from the middle of a function and then resume execution
from that point at a later time. However, the coroutine interfaces
available in C++20 are quite low-level: they are intended to be used
as building blocks for other library components rather than for
direct use by user code. Further, uncontrolled use of the type
of control flow made possible by coroutines has the potential to be
terribly confusing.
For now, avoid use of coroutines. If you have a use case that would
greatly benefit from using coroutines, please consult with software
coordination. This recommendation will be revisited for new versions
of C++ which may include easier mechanisms for using coroutines.
- *Do not use malloc, calloc, realloc, and free. Use new and delete instead.* [<<no-malloc>>]
You should avoid all memory-handling functions from the standard
...
...
@@ -2228,7 +2340,8 @@ safer possibilities.
=scanf= and =printf= are not type-safe and they are not
extensible. Use =operator>>= and =operator<<= associated with C++ streams
instead. iostream and stdio functions should never be mixed.
instead, along with =std::format= to handle formatting (see [[use-format]]).
iostream and stdio functions should never be mixed.
Example:
#+BEGIN_EXAMPLE
...
...
@@ -2249,9 +2362,8 @@ printf("This does not work: %s \n", aCPPString);
It is of course acceptable to use stdio functions if you're calling
an external library that requires them.
Admittedly, formatting using C++-style streams is more cumbersome
than a C-style format list. If you want to use =printf= style formatting,
see ``CxxUtils/StrFormat.h''.
If you need to use =printf= style formatting, see ``CxxUtils/StrFormat.h'';
however =std::format= is preferred for new code.
- *Do not use the ellipsis notation for function arguments.* [<<no-ellipsis>>]
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment