@@ -465,7 +465,7 @@ portability will be impacted.
465465Using valid ISO C++ does not guarantee portability (let alone correctness).
466466Avoid dependence on undefined behavior (e.g., [undefined order of evaluation](#Res-order))
467467and be aware of constructs with implementation defined meaning (e.g., `sizeof(int)`).
468-
468+
469469##### Note
470470
471471There are environments where restrictions on use of standard C++ language or library features are necessary, e.g., to avoid dynamic memory allocation as required by aircraft control software standards.
@@ -585,7 +585,7 @@ You don't need to write error handlers for errors caught at compile time.
585585 cerr << "Int too small\n"
586586
587587This example is easily simplified
588-
588+
589589 // Int is an alias used for integers
590590 static_assert(sizeof(Int) >= 4); // do: compile-time check
591591
@@ -594,12 +594,12 @@ This example is easily simplified
594594 void read(int* p, int n); // read max n integers into *p
595595
596596 int a[100];
597- read(a,1000); // bad
597+ read(a, 1000); // bad
598598
599599better
600600
601601 void read(span<int> r); // read into the range of integers r
602-
602+
603603 int a[100];
604604 read(a); // better: let the compiler figure out the number of elements
605605
@@ -988,7 +988,7 @@ Messy, low-level code breads more such code.
988988 if (count==sz)
989989 p = (int*) realloc(p,sizeof(int)*sz*2);
990990 // ...
991-
991+
992992This is low-level, verbose, and error-prone.
993993Insted, we could use `vector`:
994994
@@ -2687,7 +2687,7 @@ With C++11 we can write this, putting the results directly in existing local var
26872687
26882688With C++17 we should be able to use "structured bindinds" to declare and initialize the multiple variables:
26892689
2690- auto [iter,success] = myset.insert("Hello"); // C++17 structured binding
2690+ auto [iter, success] = myset.insert("Hello"); // C++17 structured binding
26912691 if (success) do_something_with(iter);
26922692
26932693##### Exception
@@ -2699,7 +2699,7 @@ For example:
26992699
27002700 istream& operator>>(istream& is, string& s); // much like std::operator>>()
27012701
2702- for (string s; cin>> s; ) {
2702+ for (string s; cin >> s; ) {
27032703 // do something with line
27042704 }
27052705
@@ -2712,11 +2712,11 @@ such as `string` and `vector`, that needs to do free store allocations.
27122712
27132713To compare, if we passed out all values as return values, we would something like this:
27142714
2715- pair<istream&,string> get_string(istream& is); // not recommended
2715+ pair<istream&, string> get_string(istream& is); // not recommended
27162716 {
27172717 string s;
2718- cin>> s;
2719- return {is,s};
2718+ cin >> s;
2719+ return {is, s};
27202720 }
27212721
27222722 for (auto p = get_string(cin); p.first; ) {
@@ -2768,24 +2768,23 @@ It complicates checking and tool support.
27682768
27692769##### Example
27702770
2771- void use(int* p, int nchar * s, int* q)
2771+ void use(int* p, int n, char * s, int* q)
27722772 {
2773- p[n-1] = 666; // Bad: we don't know if p points to n elements; assume it does not or use span<int>
2774-
2775- cout << s; // Bad: we don't know if that s points to a zero-terminated array of char; // assume it does not or use zstring
2776-
2777- delete q; // Bad: we don't know if *q is allocated on the free store; assume it does not or use owner
2773+ p[n-1] = 666; // Bad: we don't know if p points to n elements;
2774+ // assume it does not or use span<int>
2775+ cout << s; // Bad: we don't know if that s points to a zero-terminated array of char;
2776+ // assume it does not or use zstring
2777+ delete q; // Bad: we don't know if *q is allocated on the free store;
2778+ //assume it does not or use owner
27782779 }
27792780
27802781better
27812782
27822783 void use2(span<int> p, zstring s, owner<int*> q)
27832784 {
2784- p[p.size()-1] = 666; // OK, a range error can be caught
2785-
2786- cout << s; // OK
2787-
2788- delete q; // OK
2785+ p[p.size()-1] = 666; // OK, a range error can be caught
2786+ cout << s; // OK
2787+ delete q; // OK
27892788 }
27902789
27912790##### Note
@@ -6150,16 +6149,16 @@ This Shape hierarchy can be rewritten using interface inheritance:
61506149
61516150 class Shape { // pure interface
61526151 public:
6153- virtual Point center() const =0;
6154- virtual Color color() const =0;
6152+ virtual Point center() const = 0;
6153+ virtual Color color() const = 0;
61556154
6156- virtual void rotate(int) =0;
6157- virtual void move(Point p) =0;
6155+ virtual void rotate(int) = 0;
6156+ virtual void move(Point p) = 0;
61586157
6159- virtual void redraw() =0;
6158+ virtual void redraw() = 0;
61606159
61616160 // ...
6162- };
6161+ };
61636162
61646163Note that a pure interface rarely have constructors: there is nothing to construct.
61656164
@@ -6190,13 +6189,13 @@ First we devise a hierarchy of interface classes:
61906189
61916190 class Shape { // pure interface
61926191 public:
6193- virtual Point center() const =0;
6194- virtual Color color() const =0;
6192+ virtual Point center() const = 0;
6193+ virtual Color color() const = 0;
61956194
6196- virtual void rotate(int) =0;
6197- virtual void move(Point p) =0;
6195+ virtual void rotate(int) = 0;
6196+ virtual void move(Point p) = 0;
61986197
6199- virtual void redraw() =0;
6198+ virtual void redraw() = 0;
62006199
62016200 // ...
62026201 };
@@ -6258,7 +6257,7 @@ Since each implementation derived from its inteface as well as its implementatio
62586257 Smiley -> Circle -> Shape
62596258 ^ ^ ^
62606259 | | |
6261- Impl::Smiley -> Impl::Circle -> Impl::Shape
6260+ Impl::Smiley -> Impl::Circle -> Impl::Shape
62626261
62636262As mentioned, this is just one way to construct a dual hierarchy.
62646263
@@ -7479,9 +7478,12 @@ The default is the easiest to read and write.
74797478
74807479##### Example
74817480
7482- enum class Direction : char { n, s, e, w, ne, nw, se, sw }; // underlying type saves space
7481+ enum class Direction : char { n, s, e, w,
7482+ ne, nw, se, sw }; // underlying type saves space
74837483
7484- enum class Webcolor : int { red = 0xFF0000, green = 0x00FF00, blue = 0x0000FF }; // underlying type is redundant
7484+ enum class Webcolor : int { red = 0xFF0000,
7485+ green = 0x00FF00,
7486+ blue = 0x0000FF }; // underlying type is redundant
74857487
74867488##### Note
74877489
@@ -7512,9 +7514,10 @@ The default gives a consequtive set of values that is good for `switch`-statemen
75127514##### Example
75137515
75147516 enum class Col1 { red, yellow, blue };
7515- enum class Col2 { red=1, red=2, blue=2 }; // typo
7516- enum class Month { jan=1, feb, mar, apr, mar, jun, jul, august, sep, oct, nov, dec }; // starting with 1 is conventional
7517- enum class Base_flag { dec=1, oct=dec<<1, hex=dec<<2 }; // set of bits
7517+ enum class Col2 { red = 1, red = 2, blue = 2 }; // typo
7518+ enum class Month { jan = 1, feb, mar, apr, mar, jun,
7519+ jul, august, sep, oct, nov, dec }; // starting with 1 is conventional
7520+ enum class Base_flag { dec = 1, oct = dec << 1, hex = dec << 2 }; // set of bits
75187521
75197522Specifying values are neccessary to match conventional values (e.g., `Month`)
75207523and where consecutive values are undesirable (e.g., to get separate bits as in `Base_flag`).
@@ -9416,29 +9419,29 @@ Requires messy cast-and-macro-laden code to get working right.
94169419
94179420 void error(int severity ...) // ``severity'' followed by a zero-terminated list of char*s; write the C-style strings to cerr
94189421 {
9419- va_list ap; // a magic type for holding arguments
9420- va_start(ap,severity); // arg startup: "severity" is the first argument of error()
9422+ va_list ap; // a magic type for holding arguments
9423+ va_start(ap, severity); // arg startup: "severity" is the first argument of error()
94219424
9422- for (;;) {
9423- char* p = va_arg(ap,char*); // treat the next var as a char*; no checking: a cast in disguise
9424- if (p == nullptr) break;
9425- cerr << p << ' ';
9426- }
9425+ for (;;) {
9426+ char* p = va_arg(ap, char*); // treat the next var as a char*; no checking: a cast in disguise
9427+ if (p == nullptr) break;
9428+ cerr << p << ' ';
9429+ }
94279430
9428- va_end(ap); // arg cleanup (don't forget this)
9431+ va_end(ap); // arg cleanup (don't forget this)
94299432
9430- cerr << '\en ';
9431- if (severity) exit(severity);
9433+ cerr << '\n ';
9434+ if (severity) exit(severity);
94329435 }
94339436
94349437 void use()
94359438 {
9436- error(7,"this","is","an","error", nullptr);
9439+ error(7, "this", "is", "an", "error", nullptr);
94379440 error(7); // crash
9438- error(7,"this","is","an","error"); // crash
9441+ error(7, "this", "is", "an", "error"); // crash
94399442 const char* is = "is";
94409443 string an = "an";
9441- error(7,"this","is, an,"error"); // crash
9444+ error(7, "this", "is", an, "error"); // crash
94429445 }
94439446
94449447**Alternative**: Overloading. Templates. Variadic templates.
@@ -13511,10 +13514,10 @@ To say "`T` is `Sortable`":
1351113514 // requires Sortable<T> // of type T which is the name of a type
1351213515 void sort(T&); // that is Sortable"
1351313516
13514- template<Sortable T> // Better (assuming language support for concepts): "The parameter is of type T
13517+ template<Sortable T> // Better (assuming support for concepts): "The parameter is of type T
1351513518 void sort(T&); // which is Sortable"
1351613519
13517- void sort(Sortable&); // Best (assuming language support for concepts): "The parameter is Sortable"
13520+ void sort(Sortable&); // Best (assuming support for concepts): "The parameter is Sortable"
1351813521
1351913522The shorter versions better match the way we speak. Note that many templates don't need to use the `template` keyword.
1352013523
@@ -13743,9 +13746,9 @@ An incomplete set of constraints can still be very useful:
1374313746
1374413747 // balancer for a generic binary tree
1374513748 template<typename Node> concept bool Balancer = requires(Node* p) {
13746- add_fixup(p);
13747- touch(p);
13748- detach(p);
13749+ add_fixup(p);
13750+ touch(p);
13751+ detach(p);
1374913752 }
1375013753
1375113754So a `Balancer` must supply at least thee operations on a tree `Node`,
@@ -13799,7 +13802,7 @@ Two concepts requiring the same syntax but having different semantics leads to a
1379913802 template<typename I> // iterator providing random access to contiguous data
1380013803 concept bool Contiguous_iter =
1380113804 RA_iter<I> && is_contiguous<I>::value; // using is_contiguous trait
13802-
13805+
1380313806The programmer (in a library) must define `is_contiguous` (a trait) appropriately.
1380413807
1380513808Wrapping a tag class into a concept leads to a simpler expression of this idea:
@@ -13864,11 +13867,11 @@ The compiler will select the overload and emit an appropriate error.
1386413867Complementary constraints are unfortunately common in `enable_if` code:
1386513868
1386613869 template<typename T>
13867- enable_if<!C<T>,void> // bad
13870+ enable_if<!C<T>, void> // bad
1386813871 f();
1386913872
1387013873 template<typename T>
13871- enable_if<C<T>,void>
13874+ enable_if<C<T>, void>
1387213875 f();
1387313876
1387413877
@@ -14009,7 +14012,7 @@ we delay checking until instantiation time.
1400914012We consider this a worthwhile tradeoff.
1401014013
1401114014Note that using non-local, non-dependent names (such as `debug` and `cerr`) also introduce context dependencies that may lead to "mysterious" errors.
14012-
14015+
1401314016##### Note
1401414017
1401514018It can be hard to decide which properties of a type is essential and which are not.
@@ -14277,17 +14280,18 @@ Eases tool creation.
1427714280 template<typename C>
1427814281 void sort(C& c)
1427914282 {
14280- std::sort(begin(c),end(c)); // necessary and useful dependency
14283+ std::sort(begin(c), end(c)); // necessary and useful dependency
1428114284 }
1428214285
1428314286 template<typename Iter>
1428414287 Iter algo(Iter first, Iter last) {
14285- for (; first!= last; ++first) {
14288+ for (; first != last; ++first) {
1428614289 auto x = sqrt(*first); // potentially surprising dependency: which sqrt()?
14287- helper(first,x); // potentially surprising dependency: heper is chosen based on first and x
14290+ helper(first, x); // potentially surprising dependency:
14291+ // helper is chosen based on first and x
1428814292 TT var = 7; // potentially surprising dependency: which TT?
1428914293 }
14290- }
14294+ }
1429114295
1429214296##### Note
1429314297
@@ -14448,10 +14452,10 @@ This is a simplified version of `std::copy` (ignoring the possibility of non-con
1444814452
1444914453 template<class T> struct copy_trait { using tag = non_pod_tag; }; // T is not "plain old data"
1445014454
14451- template<> struct copy_trait<int> { using tab = pod_tag; }; // int is "plain old data"
14455+ template<> struct copy_trait<int> { using tab = pod_tag; }; // int is "plain old data"
1445214456
1445314457 template<class Iter>
14454- Out copy_helper(Iter first, Iter last, Iter out, pog_tag )
14458+ Out copy_helper(Iter first, Iter last, Iter out, pod_tag )
1445514459 {
1445614460 // use memmove
1445714461 }
@@ -14465,13 +14469,13 @@ This is a simplified version of `std::copy` (ignoring the possibility of non-con
1446514469 template<class Itert>
1446614470 Out copy(Iter first, Iter last, Iter out)
1446714471 {
14468- return copy_helper(first,last,out, typename copy_trait<Iter>::tag{})
14472+ return copy_helper(first, last, out, typename copy_trait<Iter>::tag{})
1446914473 }
1447014474
1447114475 void use(vector<int>& vi, vector<int>& vi2, vector<string>& vs, vector<string>& vs2)
1447214476 {
14473- copy(vi.begin(),vi.end(), vi2.begin()); // uses memmove
14474- copy(vs.begin(),vs.end(), vs2.begin()); // uses a loop calling copy constructors
14477+ copy(vi.begin(), vi.end(), vi2.begin()); // uses memmove
14478+ copy(vs.begin(), vs.end(), vs2.begin()); // uses a loop calling copy constructors
1447514479 }
1447614480
1447714481This is a general and powerful technique for compile-time algorithm selection.
@@ -14528,7 +14532,7 @@ When `concept`s become widely available such alternatives can be distinguished d
1452814532 auto x = T(u); // construction or cast?
1452914533 }
1453014534
14531- f(1,"asdf); // bad: cast from const char* to int
14535+ f(1, "asdf" ); // bad: cast from const char* to int
1453214536
1453314537##### Enforcement
1453414538
@@ -14563,10 +14567,10 @@ There are three major ways to let calling code customize a template.
1456314567
1456414568 template<class T>
1456514569 void test3(T t)
14566- // Invoke a "trait"
14567-
14568- {
14569- test_traits<T>::f(t); // require customizing test_traits<> to get non-default functions/types
14570+ // Invoke a "trait"
14571+ {
14572+ test_traits<T>::f(t); // require customizing test_traits<>
14573+ // to get non-default functions/types
1457014574 }
1457114575
1457214576A trait is usually a type alias to compute a type,
@@ -14993,15 +14997,16 @@ Documentation, readability, opportunity for reuse.
1499314997
1499414998 bool same(const Rec& a, const Rec& b)
1499514999 {
14996- return a.id== b.id;
15000+ return a.id == b.id;
1499715001 }
1499815002
1499915003 vector<Rec*> find_id(const string& name); // find all records for "name"
1500015004
15001- auto x = find_if(vr.begin(),vr.end(),
15005+ auto x = find_if(vr.begin(), vr.end(),
1500215006 [&](Rec& r) {
15003- if (r.name.size()!=n.size()) return false; // name to compare to is in n
15004- for (int i=0; i<r.name.size(); ++i) if (tolower(r.name[i])!=tolower(n[i])) return false;
15007+ if (r.name.size() != n.size()) return false; // name to compare to is in n
15008+ for (int i=0; i < r.name.size(); ++i)
15009+ if (tolower(r.name[i]) != tolower(n[i])) return false;
1500515010 return true;
1500615011 }
1500715012 );
0 commit comments