From a6b641193325e606f315cd682171a2294aadfed0 Mon Sep 17 00:00:00 2001 From: "Frank B. Brokken" Date: Sat, 24 Mar 2018 07:50:13 +0100 Subject: [PATCH 1/6] added possible coroutines chapter entry to cplusplus.yo --- annotations/yo/cplusplus.yo | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/annotations/yo/cplusplus.yo b/annotations/yo/cplusplus.yo index c532f943..0e90d752 100644 --- a/annotations/yo/cplusplus.yo +++ b/annotations/yo/cplusplus.yo @@ -116,6 +116,11 @@ COMMENT( 20 ) lchapter(THREADING)(Multi Threading) includefile(threading) +lchapter( 21 ) +chapter(Coroutines) +COMMENT(FBB: TODO, and update chapters below. See + http://www.boost.org/doc/libs/1_66_0/libs/coroutine2/doc/html) + COMMENT( 21 ) lchapter(TEMPLATES)(Function and Variable Templates) includefile(functiontemplates) From 055dd008c91a1d556b76d2eb90cf17ccfae03cae Mon Sep 17 00:00:00 2001 From: "Frank B. Brokken" Date: Sat, 24 Mar 2018 11:11:52 +0100 Subject: [PATCH 2/6] cosmetics --- annotations/yo/intro/evaluation.yo | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/annotations/yo/intro/evaluation.yo b/annotations/yo/intro/evaluation.yo index c074150d..efcbc536 100644 --- a/annotations/yo/intro/evaluation.yo +++ b/annotations/yo/intro/evaluation.yo @@ -3,8 +3,10 @@ operators is, except for the boolean operators tt(and) and tt(or), not defined. C++ changed this for postfix expressions, assignment expressions (including compound assignments), and shift operators: itemization( - it() Postfix expressions (like index operators and member selectors) - are evaluated from left to right; + it() Expressions using postfix operators (like index operators and member + selectors) are evaluated from left to right (do not confuse this with + postfix increment or decrement operators, which cannot be concatenated + (e.g., tt(variable++++) does not compile). it() Assignment expressions are evaluated from right to left; it() Operands of shift operators are evaluated from left to right. ) From 48000e80759e0978e55ee4b2ed3e6ade026f031c Mon Sep 17 00:00:00 2001 From: "Frank B. Brokken" Date: Sat, 24 Mar 2018 15:42:26 +0100 Subject: [PATCH 3/6] added first/bitfields.yo and first/designated.yo --- .../yo/advancedtemplates/availabletraits.yo | 3 +- annotations/yo/first.yo | 13 +++- annotations/yo/first/bitfields.yo | 58 ++++++++++++++++++ annotations/yo/first/designated.yo | 40 ++++++++++++ annotations/yo/memory.yo | 4 +- annotations/yo/memory/aggregate.yo | 50 +++++++++++++++ annotations/yo/memory/pod.yo | 61 ------------------- 7 files changed, 162 insertions(+), 67 deletions(-) create mode 100644 annotations/yo/first/bitfields.yo create mode 100644 annotations/yo/first/designated.yo create mode 100644 annotations/yo/memory/aggregate.yo delete mode 100644 annotations/yo/memory/pod.yo diff --git a/annotations/yo/advancedtemplates/availabletraits.yo b/annotations/yo/advancedtemplates/availabletraits.yo index 128cd808..6690ac17 100644 --- a/annotations/yo/advancedtemplates/availabletraits.yo +++ b/annotations/yo/advancedtemplates/availabletraits.yo @@ -299,7 +299,8 @@ END COMMENT) to scalar) type; itt(is_pod::value) - hi(is_pod) to determine whether tt(Type) is emi(plain old data) + hi(is_pod) to determine whether tt(Type) is an emi(aggregate) + (emi(plain old data) (em(type-condition) applies); itt(is_pointer::value) diff --git a/annotations/yo/first.yo b/annotations/yo/first.yo index 7c091eff..25545a28 100644 --- a/annotations/yo/first.yo +++ b/annotations/yo/first.yo @@ -38,14 +38,19 @@ sect(Several additions to C's grammar) subsect(Strongly typed enumerations) includefile(first/stronglytyped) - subsect(Initializer lists) + lsubsect(INILIST)(Initializer lists) includefile(first/initializer) -COMMENT(FBB: TODO: and designated initialization) + + subsubsect(Designated initialization (C++2a)) + includefile(first/designated) + + subsect(Initializers for bit-fields (C++2a)) + includefile(first/bitfields) lsubsect(AUTO)(Type inference using `auto') includefile(first/auto) - subsubsect(Structured binding declarations) + lsubsubsect(STRUCTBIND)(Structured binding declarations) includefile(first/binding) subsect(Defining types and `using' declarations) @@ -88,6 +93,8 @@ includefile(first/datatypes) subsect(The data type `size_t') includefile(first/sizet) + subsect(std::byte) + subsect(Digit separators) includefile(first/separators) diff --git a/annotations/yo/first/bitfields.yo b/annotations/yo/first/bitfields.yo new file mode 100644 index 00000000..53600a74 --- /dev/null +++ b/annotations/yo/first/bitfields.yo @@ -0,0 +1,58 @@ +Bit-fields hi(bit-field) are used to specify series of bits in an integral +value type. For example, in networking software processing IP4 packets, the +first tt(uint32_t) value of IP4 packets contain: + itemization( + it() the version (4 bits); + it() the header length (4 bits); + it() the type of service (8 bits); + it() the total length (16 bits) + ) + +Rather than using complex bit and bit-shift operations, these fields inside +integral values can be specified using bit-fields. E.g., + verb( + struct FirstIP4word + { + uint32_t version: 4; + uint32_t header: 4; + uint32_t tos: 8; + uint32_t length: 16; + }; + ) + +To total size of a tt(FirstIP4word) object is 32 bits, or four bytes. To +show the version of a tt(FirstIP4word first) object, simply do: + verb( + cout << first.version << '\n'; + ) +and to set its header length to 10 simply do + verb( + first.header = 10; + ) + +Bit fields are already available in bf(C). The tt(C++2a) standard allows them +to be initialized by default by using initialization expressions in their +definitions. E.g., + verb( + struct FirstIP4word + { + uint32_t version: 4 = 1; // version now 1, by default + uint32_t header: 4 = 10; // TCP header length now 10, by default + uint32_t tos: 8; + uint32_t length: 16; + }; + ) + The initialization expressions are evaluated when the object using the +bit-fields is defined. Also, when a variable is used to initialize a bit-field +the variable must at least have been declared when the struct containing +bit-fields is defined. E.g., + verb( + extern int value; + + struct FirstIP4word + { + ... + uint32_t length: 16 = value; // OK: value has been declared + }; + ) + diff --git a/annotations/yo/first/designated.yo b/annotations/yo/first/designated.yo new file mode 100644 index 00000000..49620254 --- /dev/null +++ b/annotations/yo/first/designated.yo @@ -0,0 +1,40 @@ +bf(C++), like bf(C), also supports emi(designated initialization). However, as +bf(C++) requires that destruction of data members occurs in the opposite order +as their construction it is required that, when using +designated initialization, members are initialized in the order in which they +are declared in their class or struct. E.g., + verb( + struct Data + { + int d_first; + double d_second; + std::string d_third; + }; + + Data data{ .d_first = 1, .d_third = "hello" }; + ) + In this example, tt(d_first) and tt(d_third) are explicitly initialized, +while tt(d_second) is implicitly initialized to its default value (so: 0.0). + +In bf(C++) it is not allowed to reorder the initialization of members in a +desginated initialization list. So, tt(Data data{ .d_third = "hello", .d_first += 1 }) is an error, but tt(Data data{ .d_third = "hello" }) is OK, as there is +no ordering conflict in the latter example (this also initializes tt(d_first) +and tt(d_second) to 0). + +Likewise, a union + hi(union: designated initialization) can be initialized using designated +initialization, as illustrated by the next example: + verb( + union Data + { + int d_first; + double d_second; + std::string *d_third; + }; + // initialize the union's d_third field: + Data data{ .d_third = new string{ "hello" } }; + ) + + + diff --git a/annotations/yo/memory.yo b/annotations/yo/memory.yo index c854142f..d0bda036 100644 --- a/annotations/yo/memory.yo +++ b/annotations/yo/memory.yo @@ -84,8 +84,8 @@ includefile(memory/moving.yo) lsect(RVO)(Copy Elision and Return Value Optimization) includefile(memory/elision.yo) -lsect(POD)(Plain Old Data) -includefile(memory/pod) +lsect(POD)(Aggregate Data Types) +includefile(memory/aggregate) sect(Conclusion) includefile(memory/conclusion) diff --git a/annotations/yo/memory/aggregate.yo b/annotations/yo/memory/aggregate.yo new file mode 100644 index 00000000..200bbdaa --- /dev/null +++ b/annotations/yo/memory/aggregate.yo @@ -0,0 +1,50 @@ +bf(C++) inherited the struct concept from bf(C) and extended it with the class +concept. Structs are still used in bf(C++), mainly to store and pass around +aggregates of different data types. A commonly used term for these structs is +emi(aggregate) (in some languages known as emi(plain old data) +(i(pod))). Aggregates are commonly used in bf(C++) programs to merely combine +data in dedicated (struct) types. E.g., when a function must return a +tt(double), a tt(bool) and tt(std::string) these three different data types +may be aggregated using a tt(struct) that merely exists to pass along +values. Data protection and functionality is hardly ever an issue. For such +cases bf(C) and bf(C++) use tt(structs). But as a bf(C++) tt(struct) is just a +tt(class) with special access rights some members (constructors, destructor, +overloaded assignment operator) may implicitly be defined. The aggregates +capitalizes on this concept by requiring that its definition remains as simple +as possible. Aggregates show the following characteristics: + itemization( + it() there are no user provided constructors or user provided inherited + constructors (cf. chapter ref(INHERITANCE)); + it() its non-static data members have public access rights; + it() no virtual members; + it() when using inheritance, the base classes aren't virtual and only + public inheritance is used. + ) + +Aggregates can also be arrays, in which case the array elements are the +aggregate's elements. If an aggregate is a tt(struct) its direct base classes +are its elements (if any), followed by the tt(struct's) data members, in their +declaration order. Here is an example: + verb( + struct Outer + { + struct Inner + { + int d_int; + double d_double; + }; + + std::string d_string; + Inner d_inner; + }; + + Outer out{ "hello", { 1, 12.5} }; + ) + tt(Outer out's d_string) is initialized with tt(hello"), its tt(d_inner) +member has two data members: tt(d_int) is initialized to 1, tt(d_double) to +12.5. + +(Designated) initializer lists can also be used (cf. section +ref(INILIST)). Also, often em(structured binding declarations) (cf. section +ref(STRUCTBIND)) can be used to avoid explicitly defining an aggregate data +type. diff --git a/annotations/yo/memory/pod.yo b/annotations/yo/memory/pod.yo deleted file mode 100644 index dcc73072..00000000 --- a/annotations/yo/memory/pod.yo +++ /dev/null @@ -1,61 +0,0 @@ -bf(C++) inherited the struct concept from bf(C) and extended it with the class -concept. Structs are still used in bf(C++), mainly to store and pass around -aggregates of different data types. A commonly used term for these structs is -emi(plain old data) (i(pod)). Plain old data is commonly used in bf(C++) -programs to aggregate data. E.g., when a function needs to return a tt(double, -bool) and tt(std::string) these three different data types may be aggregated -using a tt(struct) that merely exists to pass along values. Data protection -and functionality is hardly ever an issue. For such cases bf(C) and bf(C++) -use tt(structs). But as a bf(C++) tt(struct) is just a tt(class) with special -access rights some members (constructors, destructor, overloaded assignment -operator) may implicitly be defined. The plain old data capitalizes on this -concept by requiring that its definition remains as simple as possible. Pod is -considered any class or struct having the following characteristics: - itemization( - it() it has a i(trivial default constructor).nl() - If a type has some emi(trivial member) then the type (or its base - class(es), cf. chapter ref(INHERITANCE)) does not explicitly define - that member. Rather, it is supplied by the compiler. A trivial default - constructor leaves all its non-class data members uninitialized and - calls the default constructors of all its class data members. A class - having a trivial default constructor does not define any constructor - at all (nor does/do its base class/classes). It may also define the - default constructor using the default constructor syntax introduced in - section ref(DEFAULTED); - it() it has a i(trivial copy constructor).nl() - A trivial copy constructor byte-wise copies the non-class data members - from the provided existing class object and uses copy constructors - to initialize its base class(es) and class - data members with the information found in the provided existing class - object; - it() it has a i(trivial overloaded assignment operator).nl() - A trivial assignment operator performs a byte-wise copy of the - non-class data members of the provided right-hand class object and - uses overloaded assignment operators to assign new values to its class - data members using the corresponding members of the provided - right-hand class object; - it() it has a i(trivial destructor).nl() - A trivial destructor calls the destructors of its base class(es) and - class-type data members; - it() it has a emi(standard layout). - ) - -A em(standard-layout) class or struct - itemization( - it() has only non-static data members that are themselves showing - the standard-layout; - it() has identical access control (public, private, protected) for all its - non-static members; - ) - -Furthermore, in the context of class derivation (cf. chapters -ref(POLYMORPHISM) and ref(INHERITANCE)), a emi(standard-layout) class or -struct: - itemization( - it() has only base classes that themselves show the standard-layout; - it() has at most one (in)direct base class having non-static members; - it() has no base classes of the same type as its first non-static - data member; - it() has no virtual base classes; - it() has no virtual members. - ) From bc2f338ad591f8c30f64f17631b88b257a82b334 Mon Sep 17 00:00:00 2001 From: "Frank B. Brokken" Date: Sun, 25 Mar 2018 15:34:36 +0200 Subject: [PATCH 4/6] added section about const qualified ptrs to members --- annotations/yo/overloading.yo | 1 - annotations/yo/overloading/reference.yo | 7 ----- annotations/yo/pointermembers.yo | 3 ++ annotations/yo/pointermembers/refbinding.yo | 34 +++++++++++++++++++++ annotations/yo/preamble.yo | 3 +- 5 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 annotations/yo/pointermembers/refbinding.yo diff --git a/annotations/yo/overloading.yo b/annotations/yo/overloading.yo index 38cb051c..c559688c 100644 --- a/annotations/yo/overloading.yo +++ b/annotations/yo/overloading.yo @@ -23,7 +23,6 @@ includefile(overloading/binary.yo) lsubsect(REFBIND)(Member function reference bindings (& and &&)) includefile(overloading/reference.yo) - COMMENT(13.3.3.2) lsect(OVERLOADNEW)(Overloading `operator new(size_t)') includefile(overloading/new) diff --git a/annotations/yo/overloading/reference.yo b/annotations/yo/overloading/reference.yo index ecad9084..668b1c76 100644 --- a/annotations/yo/overloading/reference.yo +++ b/annotations/yo/overloading/reference.yo @@ -156,10 +156,3 @@ less code to write or executing fewer function calls: independent of the actual definition of the class tt(Binary). Adding standard binary operators to a class (i.e., operators operating on arguments of their own class types) can therefore easily be realized. - - - - - - - diff --git a/annotations/yo/pointermembers.yo b/annotations/yo/pointermembers.yo index 01d2e066..95c457c9 100644 --- a/annotations/yo/pointermembers.yo +++ b/annotations/yo/pointermembers.yo @@ -9,6 +9,9 @@ includefile(pointermembers/intro) sect(Using pointers to members) includefile(pointermembers/using) + subsect(A subtlety when using reference bindings (C++20)) + includefile(pointermembers/subtlety.yo) + sect(Pointers to static members) includefile(pointermembers/static) diff --git a/annotations/yo/pointermembers/refbinding.yo b/annotations/yo/pointermembers/refbinding.yo new file mode 100644 index 00000000..b6822016 --- /dev/null +++ b/annotations/yo/pointermembers/refbinding.yo @@ -0,0 +1,34 @@ +A subtlety with using pointers to members in combination with +reference bindings was observed by Mike +Spertus. Consider the following example in which a const member function +tt(fun) was declared with a reference token tt(&): + verb( + struct Demo + { + void fun() const &; + }; + ) + Although tt(fun) was declared with a tt(&) reference token, it can +nevertheless be called from an anonymous (rvalue) tt(Demo) object, because +it's a const member function: + verb( + Demo{}.fun(); // OK since C++2a + ) + However, up to the tt(C++2a) standard this function could not be called +using a pointer-to-member construction from an anonymous tt(Demo) +object. This inconsistency was solved in the tt(C++2a) standard, allowing +the following statements to be correctly compiled: + verb( + (Demo{}.*&Demo::fun)(); // using .* and fun's address (OK since C++2a) + + // previously OK: pf receives fun's address + void (Demo::*pf)() const & = &Demo::fun; + + (Demo{}.*pf)(); // call fun via the pointer pf (OK since C++2a) + ) + + + + + + diff --git a/annotations/yo/preamble.yo b/annotations/yo/preamble.yo index d04224e0..17336e33 100644 --- a/annotations/yo/preamble.yo +++ b/annotations/yo/preamble.yo @@ -1,3 +1,5 @@ +SUBST(C2a)(tt(C++2a)) + COMMENT(The following macros are used to define upcoming sections and files. Once they are available, simply remove the `c' to activate them) @@ -295,4 +297,3 @@ IFDEF(html)(\ +NOTRANS(
)\ ) )() - From c66bb32888559665fba4563782bcaf4fb67996ab Mon Sep 17 00:00:00 2001 From: "Frank B. Brokken" Date: Sun, 25 Mar 2018 15:51:44 +0200 Subject: [PATCH 5/6] added initializers to range-based for-stmnts --- annotations/yo/first.yo | 2 +- annotations/yo/first/rangebased.yo | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/annotations/yo/first.yo b/annotations/yo/first.yo index 25545a28..485df492 100644 --- a/annotations/yo/first.yo +++ b/annotations/yo/first.yo @@ -56,7 +56,7 @@ sect(Several additions to C's grammar) subsect(Defining types and `using' declarations) includefile(first/using) - subsect(Range-based for-loops) + subsect(Range-based for-loops (extension: C++2a)) includefile(first/rangebased) subsect(Raw String Literals) diff --git a/annotations/yo/first/rangebased.yo b/annotations/yo/first/rangebased.yo index 43e7f1be..c3cd5343 100644 --- a/annotations/yo/first/rangebased.yo +++ b/annotations/yo/first/rangebased.yo @@ -20,7 +20,7 @@ element of a i(range) in turn. Three types of ranges are distinguished: it() Any other type offering tt(begin()) and tt(end()) functions returning so-called em(iterators) (cf. section ref(ITERATORS)). ) - Here the following additional i(for-statement) syntax is available: + The following additional i(for-statement) syntax is available: verb( // assume int array[30] for (auto &element: array) @@ -28,9 +28,9 @@ element of a i(range) in turn. Three types of ranges are distinguished: ) The part to the left of the colon is called the emi(for range declaration). The declared variable (tt(element)) is a -formal name; use any identifier you like. The variable is only -available within the nested statement, and it refers to (or is a copy of) each -of the elements of the range, from the first element up to the last. +formal name; use any identifier you like. The variable is only available +within the nested statement, and it refers to (or is a copy of) each of the +elements of the range, from the first element up to the last. There's no formal requirement to use tt(auto), but using tt(auto) is extremely useful in many situations. Not only in situations where the range refers to @@ -69,6 +69,20 @@ elements. Instead, use references to elements: return sum; } ) + +Starting with the tt(C++2a) standard range based for loops are provided with +an optional initialization section (like the ones already available for tt(if) +and tt(switch) statements). Assume the elements of an array must be inserted +into tt(cout), but before each element we want to display the element's index. +The index variable is not used outside the tt(for)-statement, and the +extension offered in the tt(C++2a) standard allows us to localize the index +variable. Here is an example: + verb( + // localize idx: only visible in the for-stmnt + for (size_t idx = 0; auto const &element: data) + cout << idx++ << ": " << element << '\n'; + ) + COMMENT( If tt(data) is only available as a pointer to its first element in combination with the number of elements, range-based for loops can also be From f36925d6eaea12547752e62acfea146c04022f0a Mon Sep 17 00:00:00 2001 From: "Frank B. Brokken" Date: Fri, 1 Jun 2018 13:21:52 +0200 Subject: [PATCH 6/6] added mersenne twister example --- annotations/yo/stl/examples/mersenne.cc | 23 +++++++++++++++++++++++ annotations/yo/stl/randomnumber.yo | 9 +++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 annotations/yo/stl/examples/mersenne.cc diff --git a/annotations/yo/stl/examples/mersenne.cc b/annotations/yo/stl/examples/mersenne.cc new file mode 100644 index 00000000..aa28fff3 --- /dev/null +++ b/annotations/yo/stl/examples/mersenne.cc @@ -0,0 +1,23 @@ +#include +#include +#include + +using namespace std; + + // arguments: 1st: number of random numbers to generate + // 2nd: lowest positve random number, + // 3rd: highest positive random number + +int main(int argc, char **argv) +{ + mt19937 mt( time(0) ); // seed with the current time in secs. + + for ( + size_t nGenerate = stoul(argv[1]), lowest = stoul(argv[2]), + mod = stoul(argv[3]) + 1 - lowest; + nGenerate--; + ) + cout << (lowest + mt() % mod) << ' '; + + cout << '\n'; +} diff --git a/annotations/yo/stl/randomnumber.yo b/annotations/yo/stl/randomnumber.yo index bc4fa39d..0f991da7 100644 --- a/annotations/yo/stl/randomnumber.yo +++ b/annotations/yo/stl/randomnumber.yo @@ -6,12 +6,12 @@ rowfive(Class template)(Integral/Floating point)(Quality)(Speed)(Size of state) rowline() rowfive(ti(linear_congruential_engine))(Integral)(Medium)(Medium)(1) rowfive(ti(subtract_with_carry_engine))(Both)(Medium)(Fast)(25) -rowfive(mersenne_twister_engine)(Integral)(Good)(Fast)(624) +rowfive(ti(mersenne_twister_engine))(Integral)(Good)(Fast)(624) rowline() )) The ti(linear_congruential_engine) random number generator computes - center(tt(value)+subs(i+1)tt( = OPENPAa * value)subs(i)tt( + + center(tt(value)+subs(i+1)tt( = OPENPAR+a * value)subs(i)tt( + c+CLOSEPAR % m)) It expects template arguments for, respectively, the data type to contain the generated random values; the multiplier tt(a); the additive constant @@ -41,6 +41,7 @@ tt(typedef) defined by the tthi(random) header file) is used in the examples below. It can be constructed using hi(mt19937)`tt(mt19937 mt)' or it can be seeded by providing its constructor with an argument (e.g., tt(mt19937 mt(time(0)))). + Other ways to initialize the tt(mersenne_twister_engine) are beyond the scope of the annotations() (but see Lewis+hi(Lewis, P.A.W.) em(et al.)footnote( @@ -55,3 +56,7 @@ The random number generators offer members ti(min) and ti(max) returning, respectively, their minimum and maximum values (inclusive). If a reduced range is required the generators can be nested in a function or class adapting the range. + + Here's a small example showing how the tt(mersenne_twister_engine +mt19937) can be used to generate random numbers: + verbinsert(-s4 examples/mersenne)