Get started !
online LTE test
online C test

Updated or New
5G NR Data Rate calculator New
5G NR TBS calculator New
5G NR UE Registration New
Python programming
C++ programming
MIMO for 3GPP Developer - 2
Uplink power control
MIMO for 3GPP Developer
NR ARFCN and GSCN
5GS Interfaces



About
Feedback
Information Theory
Modulation
Multiple Access
DSP
OSI Model
Data Link layer
SS7
Word about ATM
GSM
GPRS
UMTS
WiMAX
LTE
CV2X
5G
Standard Reference
Reference books
Resources on Web
Miscellaneous
Mind Map
Magic MSC tool
Bar graph tool
C programming
C++ programming
Perl resources
Python programming
Javascript/HTML
MATLAB
ASCII table
Project Management

another knowledge site

3GPP Modem
Simulator


Sparkle At Office comic strip

C++ Programming

Index
1)C++ versions, documentation
2)Books on OOP and C++
3)Versions and features
4)Object Oriented Programming keywords/concepts
5)Hello World !
6)class, constructor, and destructor
7)namespace
8)Concept of "value"
9)Invariant
10)class tree/hierarchy
11)Multiple inheritance
12)static in a class
13)protected variable in a class
14)More on Constructor
15)Initialisation with "{}"
16)Delegating constructor
17)Inheriting the constructors
18)Return by reference, "&"
19)virtual function in a class
20)Forcing method (function) implementation with virtual
21)functional/function
22)Overloading the operator
23)operator "=" and copy constructor
24)Restricting operator overloading
25)Using vector template
26)Using map and its iterator
27)dynamic_cast
28)unique_ptr, shared_ptr, and weak_ptr
29)Creating template for a class
30)Variable template
31)Template specialisation
32)Copy versus move, using std::move
33)copy constructor and move constructor
34)move_iterator
35)try and catch
36)noexcept
37)enum class
38)Example of const, aka "immutable"
39)constexpr
40)Compile time if (C++ 17)
41)override
42)Restricting function override with final
43)Traversing vector
44)Function object aka functor
45)Functor with template
46)Generic Lambda expression (C++14)
47)Using Generic Lambda effectively (C++14)
48)static_assert
49)Aliases, keyword using
50)Duck typing
51)concept and requires (C++20)
52)Variadic templates
53)Fold expression, "+...+" (C++17)
54)Using std::forward
55)Critical suffix "&" (reference to)
56)RAII
57)Policy based design
58)Type checking with concept and requires
59)Containers from standard library
60)Predicate (with find_if)
61)Using random from standard library
62)Alternatives example with variant
63)Alternatives example with any
64)Using polymorphic_allocator (C++17)
65)Using for_each
66)thread and mutex
67)Another example of thread and mutex
68)thread_local
69)Automatic template argument deduction (C++17)
70)Template argument deduction guide (C++17)
71)decltype, typeid
72)decltype(auto) (C++14)
73)auto versus decltype(auto)
74)Attribute [[noreturn]]
75)Attribute [[deprecated]] (C++14)
76)Structured binding (C++17)
77)Attribute [[fallthrough]] (C++17)
78)Generalised or Nontrivial union
79)Unicode string literal
80)User defined literal
81)Concept of "value"
82)Member function's reference qualifier
83)Glossary

For executing example programs, GCC/C++20 compiler was used
(C++20 support is experimental as per GCC website).


1) C++ versions, documentation Below link lists various C++ versions and GCC support for the same:

    gcc.gnu.org

At the time of writing this article, GCC supported C++17; to use C++20, put "-std=c++20" in command line.

By checking "__cplusplus", we can determine support for the particular C++ version.

Below is a snippet code to check C++20 support.

if (__cplusplus >= 202002L) { std::cout << "C++20 supported." << std::endl; } else { std::cout << "C++20 *not* supported." << std::endl; }

Below are values of __cplusplus (Modern C++):

C++23 202302L
C++20 202002L
C++17 201703L
C++14 201402L
C++11 201103L

C++ standard is available here at isocpp.org (for purchase).

If you are looking for syntax, standard library, and such details, you may refer en.cppreference.com, cplusplus.com or devdocs.io.

2) Books on OOP and C++ For introduction to Object Oriented Programming, you may refer

    Intro to OOP by Timothy Budd

For detailed C++ (and history/origin), you may refer

    The C++ Programming Language (4th edition) by Bjarne Stroustrup (covers C++11)

For overview of C++, you may refer,

    Tour of C++ by Bjarne Stroustrup
    (2nd edition covered till C++17 and 3rd edition covers till C++20)

For C++ policy based design, you may refer,

    Modern C++ Design by Andrei Alexandrescu

For practical understanding of C++, you may refer,

    Effective Modern C++ (C++11 and C++14) by Scott Meyers

3) Versions and features This is a brief list of features. Please check Glossary if there is an example here.

C++11 auto
constexpr
for range
nullptr
enum class
static_assert
rvalue reference (std::move)
Nested template arguments
Lambda expression
Variadic template
Aliases
alignas,alignof (e.g. force 32-byte boundary, check byte boundary)
decltype
[[carries_dependency]] and [[noreturn]]
noexcept
Delegating constructor
In-class member initialiser
=default (explicitly want default constructor, say copy constructor)
=delete (do *not* want overriding or default constructor)
extern template (do *not* instantiate if so prefixed)
override
final
SFINAE - Substitution Failure Is Not An Error (compiler do *not* fail at first incorrect template match)
Memory model - concurrent access to memory
thread_local
C++14 auto as function return type
Improved constexpr
Variable templates (conditions based on T)
Generic lambda (lamda with auto parameter)
[[deprecated]] attribute
C++17 fold expression ( + ... + )
Automatic template argument deduction
Template argument deduction guide
compile time if
Structured binding
[[fallthrough]]
[[nodiscard]] (compiler warning if object returned by function is discarded)
[[maybe_unused]] (no warning even if parameter is *not* used)
C++20 concept (new library)
Modules import (*not* yet enabled in GCC)

4) Object Oriented Programming keywords/concepts Few basic concepts:

  • Classes and objects
  • Inheritance (hierarchy)
  • Polymorphism (overloading/overriding)
  • Abstraction (template)

  • 5) Hello World ! This one,

    #include <iostream> int main() { std::cout << "Hello World !" << std::endl; return 0;

    Or this one,

    #include <iostream> using namespace std; int main() { cout << "Hello World !" << endl; return 0; }

    Or this one,

    #include <iostream> using std::cout; using std::endl; int main() { cout << "Hello World !" << endl; return 0; }

    Hello World !

    6) class, constructor, and destructor Example of two classes,

    #include <iostream> class human { private: //nothing so far protected: //nothing so far public: //nothing so far }; class man : public human { public: man() // constructor { std::cout << "I am born" << std::endl; } ~man() // destructor { std::cout << "I am dying" << std::endl; } }; int main() { man Man1; std::cout << "----------" << std::endl; return 0; }

    I am born ---------- I am dying

    7) namespace Below are few methods to access names from the namespaces.

    Method 1 (preferred)

    #include <iostream> namespace human { class man { public: man() { std::cout << "I am born" << std::endl; } ~man() { std::cout << "I am dying" << std::endl; } }; } int main() { human::man Man1; std::cout << "----------" << std::endl; return 0; }

    Method 2

    #include <iostream> namespace human { class man { public: man() { std::cout << "I am born" << std::endl; } ~man() { std::cout << "I am dying" << std::endl; } }; } int main() { using namespace human; man Man1; std::cout << "----------" << std::endl; return 0; }

    Method 3

    #include <iostream> namespace human { class man { public: man() { std::cout << "I am born" << std::endl; } ~man() { std::cout << "I am dying" << std::endl; } }; } int main() { using human::man; man Man1; std::cout << "----------" << std::endl; return 0; }

    I am born ---------- I am dying

    8) Concept of "value"
    Example
    lvalue integer = 3;
    rvalue integer = 3;
    lvalue reference void update_integer(int& integer);
    rvalue reference void update_pointer_to_integer_list(int&& list_integer);


    9) Invariant Invariant is a condition that is assumed to be true for a class, and it is usually verified during the object construction.
    For example, container object like vector cannot be created with negative number of elements.

    10) class tree/hierarchy Both man and woman are derived from base class human. In below example, we have also used "nullptr".

    #include <iostream> class human { public: virtual void who_are_you(void) { std::cout << "I am a human" << std::endl; } }; class man : public human { public: void who_are_you(void) { std::cout << "I am a man" << std::endl; } }; class woman : public human { public: void who_are_you(void) { std::cout << "I am a woman" << std::endl; } }; int main() { man Man1; woman Woman1; human* ptr_human = nullptr; ptr_human = &Man1; ptr_human->who_are_you(); ptr_human = &Woman1; ptr_human->who_are_you(); std::cout << "----------" << std::endl; return 0; }

    I am a man I am a woman ----------

    11) Multiple inheritance Bjarne - "Deriving directly from more than one class is usually called multiple inheritance."

    #include <iostream> #include <string> class man { public: man() // constructor { std::cout << "man()" << std::endl; } ~man() // destructor { std::cout << "~man()" << std::endl; } std::string how_are_you(void) { return "I am good."; } }; class woman { public: woman() // constructor { std::cout << "woman()" << std::endl; } ~woman() // destructor { std::cout << "~woman()" << std::endl; } std::string how_are_you(void) { return "I am good."; } }; class indian { public: enum class region_type { north, east, south, west }; indian() // constructor { std::cout << "indian()" << std::endl; } indian(region_type ip_region) // constructor { region = ip_region; std::cout << "indian()" << std::endl; } ~indian() // destructor { std::cout << "~indian()" << std::endl; } std::string where_are_you_from(void) { switch(region) { case region_type::north: return "I am from North India."; case region_type::east: return "I am from East India."; case region_type::south: return "I am from South India."; case region_type::west: return "I am from West India."; default: break; } return "I am from India."; } private: region_type region; }; class indian_man : public man, public indian // multiple inheritance { public: using indian::indian; // inheriting constructors from indian indian_man() // constructor { std::cout << "indian_man()" << std::endl; } ~indian_man() // destructor { std::cout << "~indian_man()" << std::endl; } }; class indian_woman : public woman, public indian // multiple inheritance { public: using indian::indian; // inheriting constructors from indian indian_woman() // constructor { std::cout << "indian_woman()" << std::endl; } ~indian_woman() // destructor { std::cout << "~indian_woman()" << std::endl; } }; int main() { indian_man Man(indian::region_type::west); std::cout << "Anchor: How are you ?" << std::endl; std::cout << "Man: " << Man.how_are_you() << std::endl; std::cout << "Anchor: Where are you from ?" << std::endl; std::cout << "Man: " << Man.where_are_you_from() << std::endl; indian_woman Woman(indian::region_type::east); std::cout << "Anchor: How are you ?" << std::endl; std::cout << "Woman: " << Woman.how_are_you() << std::endl; std::cout << "Anchor: Where are you from ?" << std::endl; std::cout << "Woman: " << Woman.where_are_you_from() << std::endl; std::cout << "----------" << std::endl; return 0; }

    man() indian() Anchor: How are you ? Man: I am good. Anchor: Where are you from ? Man: I am from West India. woman() indian() Anchor: How are you ? Woman: I am good. Anchor: Where are you from ? Woman: I am from East India. ---------- ~indian_woman() ~indian() ~woman() ~indian_man() ~indian() ~man()

    12) static in a class Static variables and functions have same meaning as in C.

    #include <iostream> class human { private: static int population_ctr; protected: //nothing so far public: human() { ++population_ctr; } ~human() { --population_ctr; } static int population(void) { return population_ctr; } }; int human::population_ctr = 0; class man : public human { public: man() // constructor { std::cout << "I am born" << std::endl; } ~man() // destructor { std::cout << "I am dying" << std::endl; } }; int main() { man Man1; std::cout << "Population is " << human::population() << std::endl; std::cout << "----------" << std::endl; return 0; }

    I am born Population is 1 ---------- I am dying

    13) protected variable in a class private variables are *not* accessible to derived classes, but protected variables are.

    #include <iostream> class human { private: static unsigned int dna_stamp_ctr; protected: unsigned int dna_stamp; public: human() { dna_stamp = ++dna_stamp_ctr; } }; unsigned int human::dna_stamp_ctr = 0; class man : public human { public: man() // constructor { std::cout << "[DNA# " << dna_stamp << "] I am born" << std::endl; } ~man() // destructor { std::cout << "I am dying" << std::endl; } }; int main() { man Man1; std::cout << "----------" << std::endl; return 0; }

    [DNA# 1] I am born ---------- I am dying

    14) More on Constructor Below example illustrate shows how constructors are called and how to call parent class constructor explicitly.

    #include <iostream> #include <string> class human { private: //nothing so far protected: std::string name; public: human() { std::cout << "human()" << std::endl; } ~human() { std::cout << "~human()" << std::endl; } }; class man : public human { public: man() { std::cout << "man()" << std::endl; } man(std::string ip_name) { name = ip_name; std::cout << "man(std::string)" << std::endl; } ~man() { std::cout << "~man()" << std::endl; } }; class boy : public man { public: enum class hobby_type { sport, music, art }; boy() { std::cout << "boy()" << std::endl; } boy(std::string ip_name) : man(ip_name) // explicit call to parent class constructor { std::cout << "boy(std::string)" << std::endl; } boy(std::string ip_name, hobby_type ip_hobby) : man(ip_name), hobby(ip_hobby) { std::cout << "boy(std::string, hobby_type)" << std::endl; } ~boy() { std::cout << "~boy()" << std::endl; } private: hobby_type hobby; }; int main() { std::cout << "Creating boy ... " << std::endl; boy Boy_with_no_name; std::cout << "Creating boy with name ... " << std::endl; boy Boy_with_name("Boy"); std::cout << "Creating boy with name and hobby ... " << std::endl; boy Boy_with_hobby("Sporty boy", boy::hobby_type::sport); std::cout << "----------" << std::endl; return 0; }

    Creating boy ... human() man() boy() Creating boy with name ... human() man(std::string) boy(std::string) Creating boy with name and hobby ... human() man(std::string) boy(std::string, hobby_type) ---------- ~boy() ~man() ~human() ~boy() ~man() ~human() ~boy() ~man() ~human()

    15) Initialisation with "{}" C++11 introduced "{}" syntax for initialisation.

    #include <iostream> #include <string> class human { private: //nothing so far protected: std::string name; public: //nothing so far }; class man : public human { public: man(std::string ip_name) { name = ip_name; } }; class boy : public man { public: enum class hobby_type { sport, music, art }; boy(std::string ip_name, hobby_type ip_hobby) : man(ip_name), hobby(ip_hobby) { std::cout << "'" << name << "' with a hobby '"; switch(hobby) { case boy::hobby_type::sport: std::cout << "Sport"; break; case boy::hobby_type::music: std::cout << "Music"; break; case boy::hobby_type::art: std::cout << "Art"; break; } std::cout << "'" << std::endl; } private: hobby_type hobby; }; int main() { int basic_integer_1( 1 ); int basic_integer_2 = { 2 }; int basic_integer_3{ 3 }; int basic_integer_4 = 4; std::cout << "basic_integer_1 = " << basic_integer_1 << std::endl; std::cout << "basic_integer_2 = " << basic_integer_2 << std::endl; std::cout << "basic_integer_3 = " << basic_integer_3 << std::endl; std::cout << "basic_integer_4 = " << basic_integer_4 << std::endl; boy Boy1_with_hobby("Sporty boy", boy::hobby_type::sport); boy Boy2_with_hobby = {"Music loving boy", boy::hobby_type::music}; boy Boy3_with_hobby{"Artist boy", boy::hobby_type::art}; std::cout << "----------" << std::endl; return 0; }

    basic_integer_1 = 1 basic_integer_2 = 2 basic_integer_3 = 3 basic_integer_4 = 4 'Sporty boy' with a hobby 'Sport' 'Music loving boy' with a hobby 'Music' 'Artist boy' with a hobby 'Art' ----------

    16) Delegating constructor Instead of copying code from other constructor, we can simply call the other constructor.

    Example also shows a way to assign default values to class variable, this is known as in-class member initialiser.

    #include <iostream> #include <string> class human { private: //nothing so far protected: std::string name = "unnamed human"; // in-class member initialiser public: //nothing so far }; class man : public human { public: man(std::string ip_name) { name = ip_name; } }; class boy : public man { public: enum class hobby_type { none, sport, music, art }; boy(std::string ip_name, hobby_type ip_hobby) : man(ip_name), hobby(ip_hobby) { std::cout << "'" << name << "' with a hobby '"; switch(hobby) { case boy::hobby_type::none: std::cout << "none"; break; case boy::hobby_type::sport: std::cout << "Sport"; break; case boy::hobby_type::music: std::cout << "Music"; break; case boy::hobby_type::art: std::cout << "Art"; break; } std::cout << "'" << std::endl; } boy() : boy{"John Doe Junior", hobby_type::none} // delegating constructor or forwarding constructor { } private: hobby_type hobby; }; int main() { boy Someone; boy Boy1_with_hobby("Sporty boy", boy::hobby_type::sport); std::cout << "----------" << std::endl; return 0; }

    'John Doe Junior' with a hobby 'none' 'Sporty boy' with a hobby 'Sport' ----------

    17) Inheriting the constructors Instead re-implementing, derived class may chose to re-use the parent class constructors.

    #include <iostream> #include <string> class human { private: //nothing so far protected: std::string name; public: human() { std::cout << "human()" << std::endl; } ~human() { std::cout << "~human()" << std::endl; } }; class man : public human { public: man() { std::cout << "man()" << std::endl; } man(std::string ip_name) { name = ip_name; std::cout << "man(std::string)" << std::endl; } ~man() { std::cout << "~man()" << std::endl; } }; class boy : public man { public: using man::man; // inheriting constructors from parent class }; int main() { std::cout << "Creating boy ... " << std::endl; boy Boy_with_no_name; std::cout << "Creating boy with name ... " << std::endl; boy Boy_with_name("Boy"); // this would have failed in compilation had we not inherited the constructors std::cout << "----------" << std::endl; return 0; }

    Creating boy ... human() man() Creating boy with name ... human() man(std::string) ---------- ~man() ~human() ~man() ~human()

    18) Return by reference, "&" Return by reference is risky; use with caution.

    #include <iostream> #include <string> class person { private: std::string name; public: person() {} person(std::string ip_name) : name(ip_name) {} std::string& name_is(void) { return name; } // return by reference }; int main() { person unknown_guy; unknown_guy.name_is() = "John Doe"; std::cout << "We got " << unknown_guy.name_is() << std::endl; std::cout << "----------" << std::endl; return 0; }

    We got John Doe ----------

    19) virtual function in a class Both virtual and non-virtual functions can be overridden in derived class. However, behaviour depend on the type of object (base class or derived class) as illustrated below,

    #include <iostream> class human { public: void who_are_you_nonvirtual(void) { std::cout << "I am a human" << std::endl; } virtual void who_are_you_virtual(void) { std::cout << "I am a human" << std::endl; } }; class man : public human { public: void who_are_you_nonvirtual(void) { std::cout << "I am a man" << std::endl; } void who_are_you_virtual(void) { std::cout << "I am a man" << std::endl; } }; int main() { man Man1; human* ptr_human = &Man1; Man1.who_are_you_nonvirtual(); ptr_human->who_are_you_nonvirtual(); Man1.who_are_you_virtual(); ptr_human->who_are_you_virtual(); std::cout << "----------" << std::endl; return 0; }

    I am a man I am a human I am a man I am a man ----------

    20) Forcing method (function) implementation with virtual Setting to zero will force derived classes to provide implementation for virtual functions of base class. Below example also shows use of "string" from standard library.

    #include <iostream> #include <string> class human { protected: std::string name; public: virtual void set_name(std::string) = 0; virtual std::string get_name(void) = 0; }; class man : public human { public: void set_name(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; int main() { man Man1; Man1.set_name("Man1"); std::cout << "Man1's name is " << Man1.get_name() << std::endl; std::cout << "----------" << std::endl; return 0; }

    Man1's name is Man1 ----------

    21) functional/function Standard library functional/function is almost like function pointer, that we use in C for storing callbacks.

    #include <iostream> #include <map> #include <functional> class state { }; class engine { public: state* current_state; }; class event { }; state running; state stopped; event start; event stop; state* start_engine(state& s, event& e) { if( (&s == &stopped) && (&e == &start) ) { std::cout << "State: Stopped, Event: Start" << std::endl; std::cout << "Running now" << std::endl; return &running; } return &s; } state* stop_engine(state& s, event& e) { if( (&s == &running) && (&e == &stop) ) { std::cout << "State: Running, Event: Stop" << std::endl; std::cout << "Stopped now" << std::endl; return &stopped; } return &s; } std::function<state*(state&, event&)> state_machine[2] = { start_engine, stop_engine }; int main() { engine automobile_engine; automobile_engine.current_state = &stopped; auto number_of_start_stop_tests = 3; for(auto counter = 1; counter <= number_of_start_stop_tests; ++counter) { std::cout << "--- Iteration " << counter << " ---" << std::endl; if(automobile_engine.current_state == &stopped) automobile_engine.current_state = state_machine[0](*(automobile_engine.current_state), start); if(automobile_engine.current_state == &running) automobile_engine.current_state = state_machine[1](*(automobile_engine.current_state), stop); } std::cout << "----------" << std::endl; return 0; }

    --- Iteration 1 --- State: Stopped, Event: Start Running now State: Running, Event: Stop Stopped now --- Iteration 2 --- State: Stopped, Event: Start Running now State: Running, Event: Stop Stopped now --- Iteration 3 --- State: Stopped, Event: Start Running now State: Running, Event: Stop Stopped now ----------

    22) Overloading the operator Below code illustrates overloading stream operator "<<" (with and without friend).

    With friend

    #include <iostream> #include <string> class human { protected: std::string name; public: virtual void set_name(std::string) = 0; virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: void set_name(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; int main() { man Man1; Man1.set_name("Man1"); std::cout << "Man1's name is " << Man1 << std::endl; std::cout << "----------" << std::endl; return 0; }

    Man1's name is Man1 ----------

    Without friend

    #include <iostream> #include <string> class human { protected: std::string name; public: virtual void set_name(std::string) = 0; virtual std::string get_name(void) = 0; }; std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.get_name(); return out_stream; } class man : public human { public: void set_name(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; int main() { man Man1; Man1.set_name("Man1"); std::cout << "Man1's name is " << Man1 << std::endl; std::cout << "----------" << std::endl; return 0; }

    Man1's name is Man1 ----------

    23) operator "=" and copy constructor There are two ways in which we can create a copy of an object.
    One with assignment operator and another one with a copy constructor.
    If not explicitly defined, compiler will supply both of the above implicitly.

    human Human1; human Human2(Human1); // copy constructor human Human3; Human3 = Human1; // assignment operator


    24) Restricting operator overloading If we do not want to allow copy of humans, we can enforce it.

    #include <iostream> #include <string> class human { protected: std::string name; public: virtual void set_name(std::string) = 0; virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } void operator=(human& cp_human) = delete; }; class man : public human { public: void set_name(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; int main() { man Man1; Man1.set_name("Man1"); std::cout << "Man1's name is " << Man1 << std::endl; man Man2; Man2 = Man1; std::cout << "Man2's name is " << Man2 << std::endl; std::cout << "----------" << std::endl; return 0; }

    main.cpp: In function ‘int main()’: main.cpp:40:10: error: use of deleted function ‘man& man::operator=(man&)’

    25) Using vector template Standard library has a "template" for "vector". As the name suggests, it is an array.
    There is an interesting keyword "auto". Variable created with auto automatically takes appropriate type based on the context.

    #include <iostream> #include <string> #include <vector> class human { protected: std::string name; public: virtual void set_name(std::string) = 0; virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } void operator=(human& cp_human) = delete; }; class man : public human { public: void set_name(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; int main() { const std::int8_t number_of_waiters = 3; std::vector<man> Waiters(number_of_waiters); Waiters[0].set_name("Waiter1"); Waiters[1].set_name("Waiter2"); Waiters[2].set_name("Waiter3"); std::cout << "We have below waiters ... " << std::endl; for(auto ctr=0; ctr < number_of_waiters/*alternatively, Waiters.size()*/; ++ctr) { std::cout << "\t" << Waiters[ctr] << std::endl; } std::cout << "----------" << std::endl; return 0; }

    We have below waiters ... Waiter1 Waiter2 Waiter3 ----------

    26) Using map and its iterator map gives us a way to have non-numeric key as index. map is implemented as balanced binary tree.
    iterator allows us to traverse the (arranged) objects.

    #include <iostream> #include <string> #include <map> class human { protected: std::string name; public: virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } void operator=(human& cp_human) = delete; }; class man : public human { public: man(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; int main() { man Customer1("Customer1"), Customer2("Customer2"), Customer3("Customer3"); std::map<std::string, unsigned int> restaurant_orders; unsigned int order_ctr = 0; restaurant_orders[Customer2.get_name()] = ++order_ctr; //1 restaurant_orders[Customer1.get_name()] = ++order_ctr; //2 restaurant_orders[Customer3.get_name()] = ++order_ctr; //3 std::map<std::string, unsigned int>::iterator index_to_orders; std::cout << "Iterating orders ..." << std::endl; for(index_to_orders = restaurant_orders.begin(); index_to_orders != restaurant_orders.end(); ++index_to_orders) { std::cout << "\t" << index_to_orders->first << ", order# " << index_to_orders->second << std::endl; } std::map<std::string, unsigned int>::const_iterator index_to_orders_const; std::cout << "Iterating (const) orders ..." << std::endl; for(index_to_orders_const = restaurant_orders.cbegin(); index_to_orders_const != restaurant_orders.cend(); ++index_to_orders_const) { std::cout << "\t" << index_to_orders_const->first << ", order# " << index_to_orders_const->second << std::endl; } std::cout << "Iterating orders with 'next' ..." << std::endl; index_to_orders = restaurant_orders.begin(); while(index_to_orders != restaurant_orders.end()) { std::cout << "\t" << index_to_orders->first << ", order# " << index_to_orders->second << std::endl; index_to_orders = std::next(index_to_orders); } std::map<std::string, unsigned int>::reverse_iterator reverse_index_to_orders; std::cout << "Iterating orders in reverse ..." << std::endl; for(reverse_index_to_orders = restaurant_orders.rbegin(); reverse_index_to_orders != restaurant_orders.rend(); ++reverse_index_to_orders) { std::cout << "\t" << reverse_index_to_orders->first << ", order# " << reverse_index_to_orders->second << std::endl; } std::cout << "Iterating orders with 'prev' ..." << std::endl; index_to_orders = restaurant_orders.end(); do { index_to_orders = std::prev(index_to_orders); std::cout << "\t" << index_to_orders->first << ", order# " << index_to_orders->second << std::endl; } while(index_to_orders != restaurant_orders.begin()); std::cout << "----------" << std::endl; return 0; }

    Iterating orders ... Customer1, order# 2 Customer2, order# 1 Customer3, order# 3 Iterating (const) orders ... Customer1, order# 2 Customer2, order# 1 Customer3, order# 3 Iterating orders with 'next' ... Customer1, order# 2 Customer2, order# 1 Customer3, order# 3 Iterating orders in reverse ... Customer3, order# 3 Customer2, order# 1 Customer1, order# 2 Iterating orders with 'prev' ... Customer3, order# 3 Customer2, order# 1 Customer1, order# 2 ----------

    27) dynamic_cast With dynamic_cast succeeds if the casting is right.

    #include <iostream> class human { public: virtual void who_are_you(void) { std::cout << "I am a human" << std::endl; } }; class man : public human { public: void who_are_you(void) { std::cout << "I am a man" << std::endl; } }; class woman : public human { public: void who_are_you(void) { std::cout << "I am a woman" << std::endl; } }; int main() { man unknown_being1; std::cout << "Let us check unknown_being 1 ..." << std::endl; if(human* is_it_human = dynamic_cast<human*>(&unknown_being1)) if(man* is_it_man = dynamic_cast<man*>(&unknown_being1)) std::cout << "Human and Man !" << std::endl; else if(woman* is_it_woman = dynamic_cast<woman*>(&unknown_being1)) std::cout << "Human and Woman !" << std::endl; else std::cout << "Human, but neither Man nor Woman !" << std::endl; else std::cout << "Not human !!" << std::endl; unknown_being1.who_are_you(); woman unknown_being2; std::cout << "Let us check unknown_being 2 ..." << std::endl; if(human* is_it_human = dynamic_cast<human*>(&unknown_being2)) if(man* is_it_man = dynamic_cast<man*>(&unknown_being2)) std::cout << "Human and Man !" << std::endl; else if(woman* is_it_woman = dynamic_cast<woman*>(&unknown_being2)) std::cout << "Human and Woman !" << std::endl; else std::cout << "Human, but neither Man nor Woman !" << std::endl; else std::cout << "Not human !!" << std::endl; unknown_being2.who_are_you(); std::cout << "----------" << std::endl; return 0; }

    Let us check unknown_being 1 ... Human and Man ! I am a man Let us check unknown_being 2 ... Human and Woman ! I am a woman ----------

    28) unique_ptr, shared_ptr, and weak_ptr With unique_ptr, we can ensure to free the memory allocated for objected created with new once it is out of scope.
    shared_ptr keep track of pointers to an object, once all pointers are out of scope, object memory is freed.
    weak_ptr allows access to object pointed by shared_ptr, but it will not block the destruction of the object.
    If the object need to be accessed via weak_ptr, it can be converted to shared_ptr with lock.

    shared_ptr and weak_ptr are called smart pointers.

    #include <iostream> #include <memory> #include <string> class human { private: static unsigned int dna_stamp_ctr; protected: unsigned int dna_stamp; public: human() { dna_stamp = ++dna_stamp_ctr; } }; unsigned int human::dna_stamp_ctr = 0; class man : public human { public: std::string name = "default man"; man() // constructor { std::cout << "[DNA# " << dna_stamp << "] I am born" << std::endl; } ~man() // destructor { std::cout << "[DNA# " << dna_stamp << "] I am dying" << std::endl; } }; int main() { { man* someone_delete_me = new man(); } std::cout << "Did anyone free \"someone_delete_me\" (DNA# 1) ? If no, we have memory leak !" << std::endl; { std::cout << "Inside block1" << std::endl; std::unique_ptr<man> p_temp_worker1(new man()); } std::cout << "Out of block1" << std::endl; { std::cout << "Inside block2" << std::endl; std::shared_ptr<man> pointer_to_temp_worker = nullptr; { std::cout << "Inside block3" << std::endl; std::shared_ptr<man> p_temp_worker2(new man()); pointer_to_temp_worker = p_temp_worker2; } std::cout << "Out of block3" << std::endl; } std::cout << "Out of block2" << std::endl; { std::cout << "Inside block4" << std::endl; std::weak_ptr<man> weak_ptr_to_temp_worker; { std::cout << "Inside block5" << std::endl; std::shared_ptr<man> p_temp_worker3(new man()); weak_ptr_to_temp_worker = p_temp_worker3; if(std::shared_ptr<man> shared_ptr_to_temp_worker = weak_ptr_to_temp_worker.lock()) { std::cout << "I can access temp worker" << std::endl; std::cout << "temp worker's name is " << shared_ptr_to_temp_worker->name << std::endl; } else { std::cout << "I cannot access temp worker" << std::endl; } } std::cout << "Out of block5" << std::endl; if(weak_ptr_to_temp_worker.lock()) { std::cout << "I can access temp worker" << std::endl; } else { std::cout << "I cannot access temp worker" << std::endl; } } std::cout << "Out of block4" << std::endl; std::cout << "----------" << std::endl; return 0; }

    [DNA# 1] I am born Did anyone free "someone_delete_me" (DNA# 1) ? If no, we have memory leak ! Inside block1 [DNA# 2] I am born [DNA# 2] I am dying Out of block1 Inside block2 Inside block3 [DNA# 3] I am born Out of block3 [DNA# 3] I am dying Out of block2 Inside block4 Inside block5 [DNA# 4] I am born I can access temp worker temp worker's name is default man [DNA# 4] I am dying Out of block5 I cannot access temp worker Out of block4 ----------

    29) Creating template for a class Say, we need a group, called family and this is to include both men and women. Below is the implementation using template.
    Instead of "typename T", we could say "class T". typename allows template to be used for different type-specifiers like class, struct, and so on.
    We also used list from standard library.

    #include <iostream> #include <string> #include <list> class human { protected: std::string name; public: virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; class woman : public human { public: woman(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; template<typename T> class group { private: std::list<T*> *members; public: group() { members = new std::list<T*>; } ~group() { delete members; } void add_member(T& person) { auto member_iterator = members->begin(); members->insert(member_iterator, &person); } void print_group(void) { if(members == nullptr) return; for(auto member_iterator = members->begin(); member_iterator != members->end(); ++member_iterator) { T* member = *member_iterator; std::cout << *member << std::endl; } } void remove_member(T& person) { members->remove(&person); } }; int main() { man Husband("Husband"); woman Wife("Wife"); group<human> family; family.add_member(Husband); family.add_member(Wife); std::cout << "Family include below members " << std::endl; family.print_group(); woman Mother_in_law("Mom-in-law"); family.add_member(Mother_in_law); std::cout << "Added 1, family now include below members " << std::endl; family.print_group(); family.remove_member(Mother_in_law); std::cout << "Removed 1, family now include below members " << std::endl; family.print_group(); std::cout << "----------" << std::endl; return 0; }

    Family include below members Wife Husband Added 1, family now include below members Mom-in-law Wife Husband Removed 1, family now include below members Wife Husband ----------

    30) Variable template Variable template imply variable value based on template.

    #include <iostream> class human { private: std::string name; public: human(std::string ip_name) : name(ip_name) {} friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class bird { private: std::string name; public: bird(std::string ip_name) : name(ip_name) {} friend std::ostream& operator<<(std::ostream& out_stream, bird& ip_bird) { out_stream << ip_bird.name; return out_stream; } }; class fish { private: std::string name; public: fish(std::string ip_name) : name(ip_name) {} friend std::ostream& operator<<(std::ostream& out_stream, fish& ip_fish) { out_stream << ip_fish.name; return out_stream; } }; template<typename T> T Super = T("Super"); // variable template int main() { human Superman = Super<human>; std::cout << "This is " << Superman << " human" << std::endl; bird Superbird = Super<bird>; std::cout << "This is " << Superbird << " bird" << std::endl; fish Superfish = Super<fish>; std::cout << "This is " << Superfish << " fish" << std::endl; std::cout << "----------" << std::endl; return 0; }

    This is Super human This is Super bird This is Super fish ----------

    31) Template specialisation Yes, we can provide different template implementation for particular type(s) of template arguments.

    #include <iostream> #include <string> class human { protected: std::string name; public: friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man (std::string ip_name) { name = ip_name; } }; class baby : public human { public: baby (std::string ip_name) { name = ip_name; } }; template<typename T> void speak_up(T& person) { std::cout << "I am " << person << "." << std::endl; } // template specialisation template<> void speak_up<baby>(baby& ip_baby) { std::cout << "I am a baby, I cannot speak." << std::endl; } int main() { baby Cute_baby("Cutie"); man Father("cute baby's father"); speak_up(Cute_baby); speak_up(Father); std::cout << "----------" << std::endl; return 0; }

    I am a baby, I cannot speak. I am cute baby's father. ----------

    32) Copy versus move, using std::move Below example illustrate both Copy and Move.

    && used in operator= overloading is known as "rvalue reference".

    #include <iostream> #include <string> #include <list> class human { protected: std::string name; public: virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class woman : public human { public: woman(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; template<typename T> class group { private: std::list<T*> *members; std::string name; public: group(const std::string& ip_name) { std::cout << "group(" + ip_name + ")" << std::endl; members = new std::list<T*>; name = ip_name; } ~group() { std::cout << "~group(" + name + ")" << std::endl; delete members; } void add_member(T& person) { members->push_back(&person); } void print_group(void) { if(members == nullptr) { std::cout << "print_group(" + name + "): no members" << std::endl; return; } for(auto member_iterator = members->begin(); member_iterator != members->end(); ++member_iterator) { T* member = *member_iterator; std::cout << *member << std::endl; } } void remove_member(T& person) { members->remove(&person); } void operator=(group& ip_group) // copy (lvalue reference) { std::cout << "group operator= with copy()" << std::endl; for(auto member_iterator = ip_group.members->begin(); member_iterator != ip_group.members->end(); ++member_iterator) { T* member = *member_iterator; add_member(*member); } } void operator=(group&& ip_group) // move (rvalue reference) { std::cout << "group operator= with move()" << std::endl; members = ip_group.members; ip_group.members = nullptr; } }; int main() { woman Woman1("Woman1"); woman Woman2("Woman2"); group<woman> cool_kitty_group("cool_kitty_group"); cool_kitty_group.add_member(Woman1); cool_kitty_group.add_member(Woman2); std::cout << "Cool kitty group include below members " << std::endl; cool_kitty_group.print_group(); std::cout << "----------" << std::endl; group<woman> awesome_kitty_group("awesome_kitty_group"); awesome_kitty_group = cool_kitty_group; // copy std::cout << "After copy ...." << std::endl; std::cout << "Cool kitty group include below members " << std::endl; cool_kitty_group.print_group(); std::cout << "Awesome kitty group include below members " << std::endl; awesome_kitty_group.print_group(); std::cout << "----------" << std::endl; group<woman> renamed_cool_kitty_group("renamed_cool_kitty_group"); renamed_cool_kitty_group = std::move(cool_kitty_group); // move std::cout << "After move ...." << std::endl; std::cout << "Cool kitty group include below members " << std::endl; cool_kitty_group.print_group(); std::cout << "If no members are printed, it is ok, as we moved them and *not* copied them ! " << std::endl; std::cout << "Renamed cool kitty group include below members " << std::endl; renamed_cool_kitty_group.print_group(); std::cout << "----------" << std::endl; return 0; }

    group(cool_kitty_group) Cool kitty group include below members Woman1 Woman2 ---------- group(awesome_kitty_group) group operator= with copy() After copy .... Cool kitty group include below members Woman1 Woman2 Awesome kitty group include below members Woman1 Woman2 ---------- group(renamed_cool_kitty_group) group operator= with move() After move .... Cool kitty group include below members print_group(cool_kitty_group): no members If no members are printed, it is ok, as we moved them and *not* copied them ! Renamed cool kitty group include below members Woman1 Woman2 ---------- ~group(renamed_cool_kitty_group) ~group(awesome_kitty_group) ~group(cool_kitty_group)

    33) copy constructor and move constructor Copy and move in context of construction.

    #include <iostream> #include <iostream> #include <string> #include <list> class human { protected: std::string name; public: virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class woman : public human { public: woman(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; template<typename T> class group { private: std::list<T*> *members; std::string name; public: group(const std::string& ip_name) { std::cout << "group(" + ip_name + ")" << std::endl; members = new std::list<T*>; name = ip_name; } group(group& ip_group) // copy constructor { std::cout << "group() copy" << std::endl; members = new std::list<T*>; name = ip_group.name; for(auto member_iterator = ip_group.members->begin(); member_iterator != ip_group.members->end(); ++member_iterator) { T* member = *member_iterator; add_member(*member); } } group(group&& ip_group) // move constructor { std::cout << "group() move" << std::endl; members = ip_group.members; ip_group.members = nullptr; name = ip_group.name; } ~group() { std::cout << "~group(" + name + ")" << std::endl; delete members; } void add_member(T& person) { members->push_back(&person); } void print_group(void) { if(members == nullptr) { std::cout << "print_group(" + name + "): no members" << std::endl; return; } for(auto member_iterator = members->begin(); member_iterator != members->end(); ++member_iterator) { T* member = *member_iterator; std::cout << *member << std::endl; } } void remove_member(T& person) { members->remove(&person); } void operator=(group& ip_group) // copy (lvalue reference) { std::cout << "group operator= with copy()" << std::endl; for(auto member_iterator = ip_group.members->begin(); member_iterator != ip_group.members->end(); ++member_iterator) { T* member = *member_iterator; add_member(*member); } } void operator=(group&& ip_group) // move (rvalue reference) { std::cout << "group operator= with move()" << std::endl; members = ip_group.members; ip_group.members = nullptr; } }; int main() { woman Woman1("Woman1"); woman Woman2("Woman2"); group<woman> cool_kitty_group("cool_kitty_group"); cool_kitty_group.add_member(Woman1); cool_kitty_group.add_member(Woman2); std::cout << "Cool kitty group include below members " << std::endl; cool_kitty_group.print_group(); std::cout << "----------" << std::endl; group<woman> cool_kitty_group2(cool_kitty_group); // copy constructor std::cout << "Cool kitty group include below members " << std::endl; cool_kitty_group.print_group(); std::cout << "Cool kitty group2 include below members " << std::endl; cool_kitty_group2.print_group(); std::cout << "----------" << std::endl; group<woman> renamed_cool_kitty_group(std::move(cool_kitty_group)); // move constructor std::cout << "Cool kitty group include below members " << std::endl; cool_kitty_group.print_group(); std::cout << "If no members are printed, it is ok, as we moved them and *not* copied them ! " << std::endl; std::cout << "Renamed cool kitty group include below members " << std::endl; renamed_cool_kitty_group.print_group(); std::cout << "----------" << std::endl; return 0; }

    group(cool_kitty_group) Cool kitty group include below members Woman1 Woman2 ---------- group() copy Cool kitty group include below members Woman1 Woman2 Cool kitty group2 include below members Woman1 Woman2 ---------- group() move Cool kitty group include below members print_group(cool_kitty_group): no members If no members are printed, it is ok, as we moved them and *not* copied them ! Renamed cool kitty group include below members Woman1 Woman2 ---------- ~group(cool_kitty_group) ~group(cool_kitty_group) ~group(cool_kitty_group)

    34) move_iterator Below example has poor design, done this way only to showcase move_iterator.
    Good design will ensure moving/copying in much better way (ref: std::move example).

    #include <iostream> #include <string> #include <vector> class human { protected: std::string name; public: friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name) { name = ip_name; } }; int main() { man Man1("Man1"); man Man2("Man2"); std::vector<man> mens_cricket_team_state_karnataka = {Man1, Man2}; std::cout << "Men's team (Karanataka)..." << std::endl; for(man& team_member:mens_cricket_team_state_karnataka) std::cout << team_member << std::endl; std::cout << "----------" << std::endl; man Man3("Man3"); man Man4("Man4"); std::vector<man> mens_cricket_team_state_maharashtra = {Man3, Man4}; std::cout << "Men's team (Maharashtra)..." << std::endl; for(man& team_member:mens_cricket_team_state_maharashtra) std::cout << team_member << std::endl; std::cout << "----------" << std::endl; // copy std::vector<man> mens_cricket_team_ipl; std::copy(mens_cricket_team_state_karnataka.begin(), mens_cricket_team_state_karnataka.end(), std::back_inserter(mens_cricket_team_ipl)); std::copy(mens_cricket_team_state_maharashtra.begin(), mens_cricket_team_state_maharashtra.end(), std::back_inserter(mens_cricket_team_ipl)); std::cout << "State teams are copied to IPL team" << std::endl; std::cout << "Men's IPL team..." << std::endl; for(man& team_member:mens_cricket_team_ipl) std::cout << team_member << std::endl; std::cout << "----------" << std::endl; std::cout << "Men's team (Karanataka)..." << std::endl; for(man& team_member:mens_cricket_team_state_karnataka) std::cout << team_member << std::endl; std::cout << "----------" << std::endl; std::cout << "Men's team (Maharashtra)..." << std::endl; for(man& team_member:mens_cricket_team_state_maharashtra) std::cout << team_member << std::endl; std::cout << "----------" << std::endl; // move with move_iterator std::vector<man> mens_cricket_team_india; // in C++11, you will have to use make_move_iterator instead of move_iterator // in C++17, due to template argument deduction, this work ok std::move(std::move_iterator(mens_cricket_team_ipl.begin()), std::move_iterator(mens_cricket_team_ipl.end()), std::back_inserter(mens_cricket_team_india)); // mens_cricket_team_ipl must *not* be used std::cout << "IPL team has been moved to India team" << std::endl; std::cout << "Men's India team..." << std::endl; for(man& team_member:mens_cricket_team_india) std::cout << team_member << std::endl; std::cout << "----------" << std::endl; return 0; }

    Men's team (Karanataka)... Man1 Man2 ---------- Men's team (Maharashtra)... Man3 Man4 ---------- State teams are copied to IPL team Men's IPL team... Man1 Man2 Man3 Man4 ---------- Men's team (Karanataka)... Man1 Man2 ---------- Men's team (Maharashtra)... Man3 Man4 ---------- IPL team has been moved to India team Men's India team... Man1 Man2 Man3 Man4 ----------

    35) try and catch Below is a simple example of error handling.

    #include <iostream> #include <string> #include <list> class human { protected: std::string name; public: virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; class woman : public human { public: woman(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; template<typename T> class group { private: std::list<T*> *members; public: group() { members = new std::list<T*>; } ~group() { delete members; } void add_member(T& person) { auto member_iterator = members->begin(); members->insert(member_iterator, &person); } class error_no_list { public: std::string error_text = "group error: list not present"; }; void print_group(void) { if(members == nullptr) throw error_no_list(); for(auto member_iterator = members->begin(); member_iterator != members->end(); ++member_iterator) { T* member = *member_iterator; std::cout << *member << std::endl; } } void remove_member(T& person) { members->remove(&person); } void operator=(group&& ip_group) // move { members = ip_group.members; ip_group.members = nullptr; } }; int main() { group<human> employess_on_bench; man Employee1("Employee1"); woman Employee2("Employee2"); employess_on_bench.add_member(Employee1); employess_on_bench.add_member(Employee2); std::cout << "Employees on bench are:" << std::endl; try { employess_on_bench.print_group(); } catch(group<human>::error_no_list) { std::cout << "Error: print_group failed: '" << group<human>::error_no_list().error_text << "'" << std::endl; return 1; } catch(...) // all other errors { std::cout << "Unhandled error." << std::endl; return 2; } group<human> employess_on_work; employess_on_work = std::move(employess_on_bench); std::cout << "Employees on bench are:" << std::endl; try { employess_on_bench.print_group(); } catch(group<human>::error_no_list) { std::cout << "Error: print_group failed: '" << group<human>::error_no_list().error_text << "'" << std::endl; return 1; } catch(...) // all other errors { std::cout << "Unhandled error." << std::endl; return 2; } std::cout << "----------" << std::endl; return 0; }

    Employees on bench are: Employee2 Employee1 Employees on bench are: Error: print_group failed: 'group error: list not present'

    36) noexcept If the function is noexcept, it is assumed that it will never throw an exception.
    If it does, the program may be terminated. noexcept operator allows us to make it conditional.

    In below examples, count_population is *not* supposed to throw any exception if it is called for human.
    So it works ok in first case, but program terminates in second case.

    For bird, count_population may throw an error, so the exceptions are handled gracefully (it does *not* terminate the program).

    count_population<human> work ok

    #include <iostream> #include <regex> class human { public: const static bool traceable = true; }; class bird { public: const static bool traceable = false; }; template<typename T> bool constexpr is_traceable(void) { return T::traceable; } class counting_exception {}; template<typename T> void count_population(void) noexcept(is_traceable<T>()) { // if T is human, I can count with noexceptions // if T is bird, I may throw exceptions std::regex human_pattern {"human"}; std::regex bird_pattern {"bird"}; if(std::regex_search(typeid(T{}).name(), human_pattern)) { //..... std::cout << "Counted humans, all good !" << std::endl; } else if(std::regex_search(typeid(T{}).name(), bird_pattern)) { std::cout << "Counting birds, may face issues !" << std::endl; //...... throw counting_exception(); } } int main() { if(is_traceable<human>()) std::cout << "Humans are traceable !" << std::endl; else std::cout << "Humans are *not* traceable !" << std::endl; if(is_traceable<bird>()) std::cout << "Birds are traceable !" << std::endl; else std::cout << "Birds are *not* traceable !" << std::endl; try { count_population<bird>(); } catch(...) { std::cout << "Counting error in birds !" << std::endl; } try { count_population<human>(); } catch(...) { std::cout << "Counting error in humans !" << std::endl; } std::cout << "----------" << std::endl; return 0; }

    Humans are traceable ! Birds are *not* traceable ! Counting birds, may face issues ! Counting error in birds ! Counted humans, all good ! ----------


    count_population<human> throw exception

    #include <iostream> #include <regex> class human { public: const static bool traceable = true; }; class bird { public: const static bool traceable = false; }; template<typename T> bool constexpr is_traceable(void) { return T::traceable; } class counting_exception {}; template<typename T> void count_population(void) noexcept(is_traceable<T>()) { // if T is human, I can count with noexceptions // if T is bird, I may throw exceptions std::regex human_pattern {"human"}; std::regex bird_pattern {"bird"}; if(std::regex_search(typeid(T{}).name(), human_pattern)) { //..... std::cout << "Counting humans, something went wrong" << std::endl; throw counting_exception(); } else if(std::regex_search(typeid(T{}).name(), bird_pattern)) { //...... std::cout << "Counted birds, all good !" << std::endl; } } int main() { if(is_traceable<human>()) std::cout << "Humans are traceable !" << std::endl; else std::cout << "Humans are *not* traceable !" << std::endl; if(is_traceable<bird>()) std::cout << "Birds are traceable !" << std::endl; else std::cout << "Birds are *not* traceable !" << std::endl; try { count_population<bird>(); } catch(...) { std::cout << "Counting error in birds !" << std::endl; } try { count_population<human>(); } catch(...) { std::cout << "Counting error in humans !" << std::endl; } std::cout << "----------" << std::endl; return 0; }

    Humans are traceable ! Birds are *not* traceable ! Counted birds, all good ! Counting humans, something went wrong terminate called after throwing an instance of 'counting_exception' ./a.sh: line 6: 1893 Aborted ./a.out

    37) enum class Yes, pure (as found in C) enum and enum class are different.

    #include <iostream> #include <string> #include <vector> class human { protected: std::string name; enum class gender_t { male, female } gender; public: virtual std::string get_name(void) = 0; virtual std::string get_gender(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name) { name = ip_name; gender = gender_t::male; } std::string get_name(void) { return name; } std::string get_gender(void) { return "male"; } }; class woman : public human { public: woman(std::string ip_name) { name = ip_name; gender = gender_t::female; } std::string get_name(void) { return name; } std::string get_gender(void) { return "female"; } }; int main() { const unsigned int number_of_employees = 2; std::vector<human*> employees(number_of_employees); man Employee1("Employee1"); woman Employee2("Employee2"); employees[0] = &Employee1; employees[1] = &Employee2; std::cout << "Name\tGender" << std::endl; for(auto index = 0; index < number_of_employees; ++index) { std::cout << employees[index]->get_name() << "\t" << employees[index]->get_gender() << std::endl; } std::cout << "----------" << std::endl; return 0; }

    Name Gender Employee1 male Employee2 female ----------

    38) Example of const, aka "immutable" First program is without const and second one is with const.

    Without const

    #include <iostream> #include <string> class human { protected: std::string* name; }; class man : public human { public: man(std::string ip_name) { name = new std::string(); *name = ip_name; } ~man() { delete name; } std::string* get_name(void) { return name; } }; int main() { man Man1("Man1"); std::cout << "Man1's name is '" << *(Man1.get_name()) << "'" << std::endl; std::string* hack_name = Man1.get_name(); *hack_name = "Man2"; std::cout << "Man1's name is '" << *(Man1.get_name()) << "'" << std::endl; std::cout << "----------" << std::endl; return 0; }

    Man1's name is 'Man1' Man1's name is 'Man2' ----------

    With const

    #include <iostream> #include <string> class human { protected: std::string* name; }; class man : public human { public: man(std::string ip_name) { name = new std::string(); *name = ip_name; } ~man() { delete name; } const std::string* get_name(void) { return name; } }; int main() { man Man1("Man1"); std::cout << "Man1's name is '" << *(Man1.get_name()) << "'" << std::endl; std::string* hack_name = Man1.get_name(); *hack_name = "Man2"; std::cout << "Man1's name is '" << *(Man1.get_name()) << "'" << std::endl; std::cout << "----------" << std::endl; return 0; }

    example.cpp: In function ‘int main()’: example.cpp:33:41: error: invalid conversion from ‘const string*’ {aka ‘const std::__cxx11::basic_string<char>*’} to ‘std::string*’ {aka ‘std::__cxx11::basic_string<char>*’} [-fpermissive]

    39) constexpr constexpr is more like C macro i.e. it is evaluated at compile time.
    For example, constexpr double PI = ((double)22)/7;.

    constexpr could be a function (including constructors).
    If possible, it is evaluated at compile time, otherwise at runtime.

    #include <iostream> constexpr double get_me_PI(void) { return ((double)22)/7; // compile time } constexpr double get_me_area_of_circle(unsigned int radius) { return get_me_PI()*radius*radius; // runtime } int main() { unsigned int circle1_radius; std::cout << "Enter radius: "; std::cin >> circle1_radius; std::cout << "Area of circle with radius " << circle1_radius; std::cout << " unit is " << get_me_area_of_circle(circle1_radius) << " unit-square." << std::endl; std::cout << "----------" << std::endl; return 0; }

    Enter radius: 4 Area of circle with radius 4 unit is 50.2857 unit-square. ----------

    40) Compile time if (C++ 17) Below is an example of using constexpr in if statement.

    #include <iostream> namespace rel1 { void basic_processing(void) { std::cout << "basic_processing()" << std::endl; } } namespace rel2 { const bool enabled = true; void enhanced_processing(void) { std::cout << "enhanced_processing()" << std::endl; } } namespace rel3 { const bool enabled = false; void ultra_enhanced_processing(void) { std::cout << "ultra_enhanced_processing()" << std::endl; } } int main() { using namespace rel1; if constexpr(rel3::enabled) { rel3::ultra_enhanced_processing(); } else if constexpr(rel2::enabled) { rel2::enhanced_processing(); } else { basic_processing(); } std::cout << "----------" << std::endl; return 0; }

    enhanced_processing() ----------

    41) override If override is added to a member function, it makes it explicit to compiler that derived class is overriding the parent class function.

    In below example, mute_check has been misspelled in class mute_person.
    Without override, program compiles, but gives incorrect result.
    With override, the error is caught.

    Without override

    #include <iostream> #include <string> #include <vector> class person { protected: std::string name; public: person(std::string ip_name) : name(ip_name) {} virtual bool mute_check(void) { return false; } friend std::ostream& operator<<(std::ostream& out_stream, person& ip_person) { out_stream << ip_person.name; return out_stream; } }; class mute_person : public person { public: mute_person(std::string ip_name) : person(ip_name) {} bool mute_chuck(void) { return true; } }; int main() { person Person1("Person1"); mute_person Person2("Person2"); std::vector<person*> people{&Person1, &Person2}; for(auto p : people) { if(p->mute_check()) std::cout << *p << " is mute" << std::endl; else std::cout << *p << " is *not* mute" << std::endl; } std::cout << "----------" << std::endl; return 0; }

    Person1 is *not* mute Person2 is *not* mute ----------


    With override

    #include <iostream> #include <string> #include <vector> class person { protected: std::string name; public: person(std::string ip_name) : name(ip_name) {} virtual bool mute_check(void) { return false; } friend std::ostream& operator<<(std::ostream& out_stream, person& ip_person) { out_stream << ip_person.name; return out_stream; } }; class mute_person : public person { public: mute_person(std::string ip_name) : person(ip_name) {} bool mute_chuck(void) override { return true; } }; int main() { person Person1("Person1"); mute_person Person2("Person2"); std::vector<person*> people{&Person1, &Person2}; for(auto p : people) { if(p->mute_check()) std::cout << *p << " is mute" << std::endl; else std::cout << *p << " is *not* mute" << std::endl; } std::cout << "----------" << std::endl; return 0; }

    example.cpp:21:10: error: ‘bool mute_person::mute_chuck()’ marked ‘override’, but does not override 21 | bool mute_chuck(void) override { return true; }

    42) Restricting function override with final final ensures that function is not overloaded (by derived classes).

    #include <iostream> #include <string> class human { protected: std::string name; public: virtual std::string get_name(void) final { return name; } friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; int main() { man Man1("Man1") std::cout << Man1 << std::endl; std::cout << "----------" << std::endl; return 0; }

    example.cpp:26:17: error: virtual function ‘virtual std::string man::get_name()’ overriding final function 26 | std::string get_name(void)

    43) Traversing vector Though example is for vector, it is applicable to list and other sequences.

    #include <iostream> #include <string> #include <vector> class human { protected: std::string name; public: virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; class woman : public human { public: woman(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; int main() { const unsigned int number_of_employees = 2; std::vector<human*> employees(number_of_employees); man Employee1("Employee1"); woman Employee2("Employee2"); employees[0] = &Employee1; employees[1] = &Employee2; std::cout << "Traversing employees ..." << std::endl; for(auto employee : employees) //vector supports begin() and end() { std::cout << *employee << std::endl; } std::cout << "----------" << std::endl; return 0; }

    Traversing employees ... Employee1 Employee2 ----------

    44) Function object aka functor Like objects, Function objects have their own variables and multiple copies can be created of it.
    Function object is often called callable object.

    You may compare it (in limited way) with static variables inside a function in C.

    #include <iostream> #include <string> #include <vector> class human { protected: std::string name; unsigned int height; // in centimeter unsigned int weight; // in grams public: virtual std::string get_name(void) final { return name; } virtual unsigned int get_height(void) final { return height; } virtual unsigned int get_weight(void) final { return weight; } friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name, unsigned short ip_height, unsigned int ip_weight) { name = ip_name; height = ip_height; weight = ip_weight; } }; class ref_measurement { private: unsigned int ref_val; public: ref_measurement(unsigned int ip_val):ref_val(ip_val) {} bool operator()(unsigned int compare_val) { return compare_val > ref_val; } }; constexpr unsigned int average_height = 167; ref_measurement more_than_ref_height(average_height); constexpr unsigned int average_weight = 60000; ref_measurement more_than_ref_weight(average_weight); int main() { man Man1("Man1", 183, 80000); man Boy1("Boy1", 152, 65000); std::vector<human*> candidates(2); candidates[0] = &Man1; candidates[1] = &Boy1; for(auto p_candidate : candidates) { std::cout << "----------" << std::endl; if(more_than_ref_height(p_candidate->get_height())) std::cout << *p_candidate << " has above average height" << std::endl; else std::cout << *p_candidate << " has below average height" << std::endl; if(more_than_ref_weight(p_candidate->get_weight())) std::cout << *p_candidate << " has above average weight" << std::endl; else std::cout << *p_candidate << " has below average weight" << std::endl; } std::cout << "----------" << std::endl; return 0; }

    ---------- Man1 has above average height Man1 has above average weight ---------- Boy1 has below average height Boy1 has above average weight ----------

    45) Functor with template template will allow further generic implementation.

    #include <iostream> #include <string> #include <vector> class human { protected: std::string name; unsigned int height; // in centimeter unsigned int weight; // in grams public: virtual std::string get_name(void) final { return name; } virtual unsigned int get_height(void) final { return height; } virtual unsigned int get_weight(void) final { return weight; } friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name, unsigned short ip_height, unsigned int ip_weight) { name = ip_name; height = ip_height; weight = ip_weight; } }; template<typename T> class ref_measurement { private: const T ref_val; public: ref_measurement(const T& ip_val):ref_val(ip_val) {} bool operator()(const T& compare_val) const { return compare_val > ref_val; } }; constexpr unsigned int average_height = 167; ref_measurement<unsigned int> more_than_ref_height(average_height); constexpr unsigned int average_weight = 60000; ref_measurement<unsigned int> more_than_ref_weight(average_weight); int main() { man Man1("Man1", 183, 80000); man Boy1("Boy1", 152, 65000); std::vector<human*> candidates(2); candidates[0] = &Man1; candidates[1] = &Boy1; for(auto p_candidate : candidates) { std::cout << "----------" << std::endl; if(more_than_ref_height(p_candidate->get_height())) std::cout << *p_candidate << " has above average height" << std::endl; else std::cout << *p_candidate << " has below average height" << std::endl; if(more_than_ref_weight(p_candidate->get_weight())) std::cout << *p_candidate << " has above average weight" << std::endl; else std::cout << *p_candidate << " has below average weight" << std::endl; } std::cout << "----------" << std::endl; return 0; }

    ---------- Man1 has above average height Man1 has above average weight ---------- Boy1 has below average height Boy1 has above average weight ----------

    46) Generic Lambda expression (C++14) "[](){}" is a Lambda expression. It is basically function on the fly.
    It stands for "[captured variables](input parameters){implementation}".
    In below example, more_than_ref_height and more_than_ref_weight do very similar processing, but former uses input parameters and latter uses captured variables.

    #include <iostream> #include <string> #include <vector> class human { protected: std::string name; unsigned int height; // in centimeter unsigned int weight; // in grams public: virtual std::string get_name(void) final { return name; } virtual unsigned int get_height(void) final { return height; } virtual unsigned int get_weight(void) final { return weight; } friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name, unsigned short ip_height, unsigned int ip_weight) { name = ip_name; height = ip_height; weight = ip_weight; } }; constexpr unsigned int average_height = 167; constexpr unsigned int average_weight = 60000; auto more_than_ref_height = [](unsigned int l_height){ return (l_height > average_height); }; int main() { man Man1("Man1", 183, 80000); man Boy1("Boy1", 152, 65000); std::vector<human*> candidates(2); candidates[0] = &Man1; candidates[1] = &Boy1; for(auto p_candidate : candidates) { std::cout << "----------" << std::endl; if(more_than_ref_height(p_candidate->get_height())) std::cout << *p_candidate << " has above average height" << std::endl; else std::cout << *p_candidate << " has below average height" << std::endl; auto more_than_ref_weight = [p_candidate](){ return (p_candidate->get_weight() > average_weight); }; if(more_than_ref_weight()) std::cout << *p_candidate << " has above average weight" << std::endl; else std::cout << *p_candidate << " has below average weight" << std::endl; } std::cout << "----------" << std::endl; return 0; }

    ---------- Man1 has above average height Man1 has above average weight ---------- Boy1 has below average height Boy1 has above average weight ----------

    47) Using Generic Lambda effectively (C++14) Clever use of auto and Lambda's capture capability indeed.

    #include <iostream> auto table_of_x = [](int x) { auto multiply = [x](int n) { return x * n; }; return multiply; }; int main() { const int counters[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; auto table_of_2 = table_of_x(2); auto table_of_3 = table_of_x(3); for (auto n:counters) std::cout << "2 * " << n << " = " << table_of_2(n) << std::endl; std::cout << "----------" << std::endl; for (auto n:counters) std::cout << "3 * " << n << " = " << table_of_3(n) << std::endl; std::cout << "----------" << std::endl; return 0; }

    2 * 1 = 2 2 * 2 = 4 2 * 3 = 6 2 * 4 = 8 2 * 5 = 10 2 * 6 = 12 2 * 7 = 14 2 * 8 = 16 2 * 9 = 18 2 * 10 = 20 ---------- 3 * 1 = 3 3 * 2 = 6 3 * 3 = 9 3 * 4 = 12 3 * 5 = 15 3 * 6 = 18 3 * 7 = 21 3 * 8 = 24 3 * 9 = 27 3 * 10 = 30 ----------

    48) static_assert static_assert is basically to do a compile time check.
    Below example also uses utility called is_assignable from standard library.

    #include <iostream> template<typename T1, typename T2> void compile_time_compatibility_check() { static_assert(std::is_assignable<T1, T2>::value, "Not compatible"); }; class human { }; class man : public human { }; class alien { }; int main() { compile_time_compatibility_check<human, man>(); // OK compile_time_compatibility_check<man, human>(); // assertion 'Not compatible' compile_time_compatibility_check<alien, human>(); // assertion 'Not compatible' return 0; }

    example.cpp: In instantiation of ‘void compile_time_compatibility_check() [with T1 = man; T2 = human]’: example.cpp:20:47: required from here example.cpp:5:45: error: static assertion failed: Not compatible 5 | static_assert(std::is_assignable<T1, T2>::value, "Not compatible"); | ^~~~~ example.cpp:5:45: note: ‘std::integral_constant<bool, false>::value’ evaluates to false example.cpp: In instantiation of ‘void compile_time_compatibility_check() [with T1 = alien; T2 = human]’: example.cpp:21:49: required from here example.cpp:5:45: error: static assertion failed: Not compatible example.cpp:5:45: note: ‘std::integral_constant<bool, false>::value’ evaluates to false

    49) Aliases, keyword using using keyword allows us to create aliases (synonyms) for types and templates.

    #include <iostream> #include <string> #include <list> class human { protected: std::string name; public: virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; class woman : public human { public: woman(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; template<typename T> class group { private: std::list<T*> *members; public: group() { members = new std::list<T*>; } ~group() { delete members; } void add_member(T& person) { auto member_iterator = members->begin(); members->insert(member_iterator, &person); } void print_group(void) { if(members == nullptr) return; for(auto member_iterator = members->begin(); member_iterator != members->end(); ++member_iterator) { T* member = *member_iterator; std::cout << *member << std::endl; } } void remove_member(T& person) { members->remove(&person); } }; // aliases using mens_group = group<man>; using womens_group = group<woman>; int main() { mens_group mens_soccer_team; man Man1("Man1"); man Man2("Man2"); mens_soccer_team.add_member(Man1); mens_soccer_team.add_member(Man2); std::cout << "Soccer team:" << std::endl; mens_soccer_team.print_group(); womens_group kitty_group; woman Woman1("Woman1"); woman Woman2("Woman2"); kitty_group.add_member(Woman1); kitty_group.add_member(Woman2); std::cout << "Kitty group:" << std::endl; kitty_group.print_group(); std::cout << "----------" << std::endl; return 0; }

    Soccer team: Man2 Man1 Kitty group: Woman2 Woman1 ----------

    50) Duck typing Though we had created group template for human, alien also was able to use the template.
    This was possible as alien behaved same way as human !
    This is known as Duck typing (looks like duck, quacks like duck, so it is a duck).

    #include <iostream> #include <string> #include <list> class human { protected: std::string name; public: virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; class woman : public human { public: woman(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; template<typename T> class group { private: std::list<T*> *members; public: group() { members = new std::list<T*>; } ~group() { delete members; } void add_member(T& person) { auto member_iterator = members->begin(); members->insert(member_iterator, &person); } void print_group(void) { if(members == nullptr) return; for(auto member_iterator = members->begin(); member_iterator != members->end(); ++member_iterator) { T* member = *member_iterator; std::cout << *member << std::endl; } } void remove_member(T& person) { members->remove(&person); } }; class alien { private: std::string name; public: alien(std::string ip_name) { name = ip_name; } friend std::ostream& operator<<(std::ostream& out_stream, alien& ip_alien) { out_stream << ip_alien.name; return out_stream; } }; int main() { group<alien> secret_group; alien Neila1("Neila1"), Neila2("Neila2"); secret_group.add_member(Neila1); secret_group.add_member(Neila2); std::cout << "Secret group has below members:" << std::endl; secret_group.print_group(); std::cout << "----------" << std::endl; return 0; }

    Secret group has below members: Neila2 Neila1 ----------

    51) concept and requires (C++20) To ensure that duck typing do not happen, we need certain compile time checks.
    This is possible with C++20 requires.

    Without concept

    #include <iostream> #include <string> #include <list> class human { private: static unsigned int human_dna_ctr; protected: std::string name; static unsigned int human_dna; public: human() { human_dna = ++human_dna_ctr; } virtual unsigned int get_human_dna(void) final { return human_dna; } friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name) { name = ip_name; } }; class woman : public human { public: woman(std::string ip_name) { name = ip_name; } }; template<typename T> requires requires(T a) { a.get_human_dna(); } class group { private: std::list<T*> *members; public: group() { members = new std::list<T*>; } ~group() { delete members; } void add_member(T& person) { auto member_iterator = members->begin(); members->insert(member_iterator, &person); } void print_group(void) { if(members == nullptr) return; for(auto member_iterator = members->begin(); member_iterator != members->end(); ++member_iterator) { T* member = *member_iterator; std::cout << *member << std::endl; } } void remove_member(T& person) { members->remove(&person); } }; class alien { private: std::string name; public: alien(std::string ip_name) { name = ip_name; } friend std::ostream& operator<<(std::ostream& out_stream, alien& ip_alien) { out_stream << ip_alien.name; return out_stream; } }; int main() { group<man> mens_soccer_team; group<alien> secret_group; std::cout << "----------" << std::endl; return 0; }

    example.cpp: In function ‘int main()’: example.cpp:96:14: error: template constraint failure for ‘template<class T> requires requires(T a) {a.get_human_dna();} class group’

    With concept

    #include <iostream> #include <string> #include <list> class human { private: static unsigned int human_dna_ctr; protected: std::string name; static unsigned int human_dna; public: human() { human_dna = ++human_dna_ctr; } virtual unsigned int get_human_dna(void) final { return human_dna; } friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name) { name = ip_name; } }; class woman : public human { public: woman(std::string ip_name) { name = ip_name; } }; template <typename T> concept requires_human_dna = requires(T a) { a.get_human_dna(); }; template<typename T> requires requires_human_dna<T> class group { private: std::list<T*> *members; public: group() { members = new std::list<T*>; } ~group() { delete members; } void add_member(T& person) { auto member_iterator = members->begin(); members->insert(member_iterator, &person); } void print_group(void) { if(members == nullptr) return; for(auto member_iterator = members->begin(); member_iterator != members->end(); ++member_iterator) { T* member = *member_iterator; std::cout << *member << std::endl; } } void remove_member(T& person) { members->remove(&person); } }; class alien { private: std::string name; public: alien(std::string ip_name) { name = ip_name; } friend std::ostream& operator<<(std::ostream& out_stream, alien& ip_alien) { out_stream << ip_alien.name; return out_stream; } }; int main() { group<man> mens_soccer_team; group<alien> secret_group; std::cout << "----------" << std::endl; return 0; }

    example.cpp: In function ‘int main()’: example.cpp:99:14: error: template constraint failure for ‘template<class T> requires requires_human_dna<T> class group’

    52) Variadic templates template with variable number of arguments is a Variadic template.
    Below is a recursive implementation of one such template.

    #include <iostream> #include <string> class human { protected: std::string name; public: virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } virtual bool above_18(void) = 0; }; class man : public human { public: man() {} man(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } bool above_18(void) { return true; } }; class boy : public man { public: boy(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } bool above_18(void) { return false; } }; class woman : public human { public: woman() {} woman(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } bool above_18(void) { return true; } }; bool pub_entry_allowed() { return true; } template<typename T, typename... Rest> bool pub_entry_allowed(T& first, Rest&... rest) { if(first.above_18()) return pub_entry_allowed(rest...); // recursive ! else return false; }; int main() { man Man1("Man1"); woman Woman1("Woman1"); boy Boy1("Boy1"); bool allowed_or_not = pub_entry_allowed(Man1, Boy1, Woman1); if(allowed_or_not) std::cout << "Entry into pub allowed for group {Man1, Boy1, Woman1}." << std::endl; else std::cout << "Entry into pub *not* allowed for group {Man1, Boy1, Woman1}." << std::endl; allowed_or_not = pub_entry_allowed(Man1, Woman1); if(allowed_or_not) std::cout << "Entry into pub allowed for group {Man1, Woman1}." << std::endl; else std::cout << "Entry into pub *not* allowed for group {Man1, Woman1}." << std::endl; std::cout << "----------" << std::endl; return 0; }

    Entry into pub *not* allowed for group {Man1, Boy1, Woman1}. Entry into pub allowed for group {Man1, Woman1}. ----------

    53) Fold expression, "+...+" (C++17) Fold expression is created to simplify implementation of variadic templates.

    #include <iostream> #include <string> #include <list> class human { protected: std::string name; public: virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man() {} man(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; class boy : public man { public: boy(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; class woman : public human { public: woman() {} woman(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; template<typename T> class group { private: std::list<T*> *members; public: group() { std::cout << "group()" << std::endl; members = new std::list<T*>; } ~group() { std::cout << "~group()" << std::endl; delete members; } void add_member(T& person) { members->push_back(&person); } void print_group(void) { if(members == nullptr) return; for(auto member_iterator = members->begin(); member_iterator != members->end(); ++member_iterator) { T* member = *member_iterator; std::cout << *member << std::endl; } } void remove_member(T& person) { members->remove(&person); } }; group<human>& operator+(group<human>& ip_group, human& Human1) { std::cout << "group operator+(): " << Human1 << std::endl; ip_group.add_member(Human1); return ip_group; } template<typename... T> void form_group(group<human>& ip_group, T&... people) // alternatively, group<human>& form_group(group<human>& ip_group, T&... people) { std::cout << "form_group()" << std::endl; (ip_group +...+ people); // fold expression // alternatively, return (ip_group +...+ people); } int main() { man Man1("Man1"); woman Woman1("Woman1"); boy Boy1("Boy1"); group<human> general_group; form_group(general_group, Man1, Woman1, Boy1); // alternatively, general_group = form_group(general_group, Man1, Woman1, Boy1); std::cout << "----------" << std::endl; std::cout << "general_group has below below members " << std::endl; general_group.print_group(); std::cout << "----------" << std::endl; return 0; }

    group() form_group() group operator+(): Man1 group operator+(): Woman1 group operator+(): Boy1 ---------- general_group has below below members Man1 Woman1 Boy1 ---------- ~group()

    54) Using std::forward When arguments are passed from function to function, intermediate functions should be able transparently forward the arguments, we may call it "perfect forwarding".

    std::move will work too, however intermediate functions will have to know the types and number of arguments.

    #include <iostream> #include <string> class SRB_Channel_Configuration { public: int srb_cfg_parameter; SRB_Channel_Configuration() { std::cout << "SRB_Channel_Configuration()" << std::endl; } SRB_Channel_Configuration(int ip_srb_cfg_parameter) : srb_cfg_parameter(ip_srb_cfg_parameter) { std::cout << "SRB_Channel_Configuration()" << std::endl; } ~SRB_Channel_Configuration() { std::cout << "~SRB_Channel_Configuration()" << std::endl; } }; class UE_Channel_SRB { public: int srb_cfg; int additional_config; void Configure(SRB_Channel_Configuration& configuration, int ip_additional_config) { std::cout << "UE_Channel_SRB.Configure(lvalue reference)" << std::endl; srb_cfg = configuration.srb_cfg_parameter; additional_config = ip_additional_config; } void Configure(SRB_Channel_Configuration&& configuration, int ip_additional_config) { std::cout << "UE_Channel_SRB.Configure(rvalue reference)" << std::endl; srb_cfg = configuration.srb_cfg_parameter; additional_config = ip_additional_config; } void print_configuration(void) { std::cout << "srb_cfg = " << srb_cfg << std::endl; std::cout << "additional_config = " << additional_config << std::endl; } }; enum class srb_channel_type { SRB0, SRB1 }; class UE_MAC { public: UE_Channel_SRB srb0_channel; UE_Channel_SRB srb1_channel; template<typename... T> void SRB_Configure(srb_channel_type ch_type, T&&... Configuration) { switch(ch_type) { case srb_channel_type::SRB0: srb0_channel.Configure(std::forward<T>(Configuration)...); break; case srb_channel_type::SRB1: srb1_channel.Configure(std::forward<T>(Configuration)...); break; default: break; } } void print_configuration(void) { std::cout << "SRB0 configuration:" << std::endl; srb0_channel.print_configuration(); std::cout << "SRB1 configuration:" << std::endl; srb1_channel.print_configuration(); } }; class UE_RRC { public: UE_MAC* p_ue_mac = nullptr; UE_RRC(UE_MAC* const ip_p_ue_mac) : p_ue_mac(ip_p_ue_mac) {} template<typename... T> void SRB_Configure(srb_channel_type ch_type, T&&... Configuration) { p_ue_mac->SRB_Configure(ch_type, std::forward<T>(Configuration)...); } }; int main() { UE_MAC ue_mac; UE_RRC ue_rrc(&ue_mac); ue_rrc.SRB_Configure(srb_channel_type::SRB0, SRB_Channel_Configuration{0}, 123); std::cout << "----------" << std::endl; SRB_Channel_Configuration srb1_configuration{1}; ue_rrc.SRB_Configure(srb_channel_type::SRB1, srb1_configuration, 456); std::cout << "----------" << std::endl; ue_mac.print_configuration(); std::cout << "----------" << std::endl; return 0; }

    SRB_Channel_Configuration() UE_Channel_SRB.Configure(rvalue reference) ~SRB_Channel_Configuration() ---------- SRB_Channel_Configuration() UE_Channel_SRB.Configure(lvalue reference) ---------- SRB0 configuration: srb_cfg = 0 additional_config = 123 SRB1 configuration: srb_cfg = 1 additional_config = 456 ---------- ~SRB_Channel_Configuration()

    55) Critical suffix "&" (reference to) Please refer one of earlier examples rewritten with and without "&" in function pub_entry_allowed.

    With "&"

    #include <iostream> #include <string> class human { protected: std::string name; public: human() { std::cout << "Human born" << std::endl; } human(human&) // copy constructor { std::cout << "Human copied" << std::endl; } ~human() { std::cout << "Human died" << std::endl; } virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } virtual bool above_18(void) = 0; }; class man : public human { public: man() {} man(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } bool above_18(void) { return true; } }; class boy : public man { public: boy(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } bool above_18(void) { return false; } }; class woman : public human { public: woman() {} woman(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } bool above_18(void) { return true; } }; bool pub_entry_allowed() { return true; } template<typename T, typename... Rest> bool pub_entry_allowed(T& first, Rest&... rest) { if(first.above_18()) return pub_entry_allowed(rest...); // recursive ! else return false; }; int main() { man Man1("Man1"); woman Woman1("Woman1"); boy Boy1("Boy1"); bool allowed_or_not = pub_entry_allowed(Man1, Boy1, Woman1); if(allowed_or_not) std::cout << "Entry into pub allowed for group {Man1, Boy1, Woman1}." << std::endl; else std::cout << "Entry into pub *not* allowed for group {Man1, Boy1, Woman1}." << std::endl; allowed_or_not = pub_entry_allowed(Man1, Woman1); if(allowed_or_not) std::cout << "Entry into pub allowed for group {Man1, Woman1}." << std::endl; else std::cout << "Entry into pub *not* allowed for group {Man1, Woman1}." << std::endl; std::cout << "----------" << std::endl; return 0; }

    Human born Human born Human born Entry into pub *not* allowed for group {Man1, Boy1, Woman1}. Entry into pub allowed for group {Man1, Woman1}. ---------- Human died Human died Human died

    There are equal (3) of "born and "died", so copy was avoided.
    If we do not use "&", we end up in multiple copy operations as seen below.

    Without "&"

    #include <iostream> #include <string> class human { protected: std::string name; public: human() { std::cout << "Human born" << std::endl; } human(human&) // copy constructor { std::cout << "Human copied" << std::endl; } ~human() { std::cout << "Human died" << std::endl; } virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } virtual bool above_18(void) = 0; }; class man : public human { public: man() {} man(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } bool above_18(void) { return true; } }; class boy : public man { public: boy(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } bool above_18(void) { return false; } }; class woman : public human { public: woman() {} woman(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } bool above_18(void) { return true; } }; bool pub_entry_allowed() { return true; } template<typename T, typename... Rest> bool pub_entry_allowed(T first, Rest... rest) { if(first.above_18()) return pub_entry_allowed(rest...); // recursive ! else return false; }; int main() { man Man1("Man1"); woman Woman1("Woman1"); boy Boy1("Boy1"); bool allowed_or_not = pub_entry_allowed(Man1, Boy1, Woman1); if(allowed_or_not) std::cout << "Entry into pub allowed for group {Man1, Boy1, Woman1}." << std::endl; else std::cout << "Entry into pub *not* allowed for group {Man1, Boy1, Woman1}." << std::endl; allowed_or_not = pub_entry_allowed(Man1, Woman1); if(allowed_or_not) std::cout << "Entry into pub allowed for group {Man1, Woman1}." << std::endl; else std::cout << "Entry into pub *not* allowed for group {Man1, Woman1}." << std::endl; std::cout << "----------" << std::endl; return 0; }

    Human born Human born Human born Human copied Human copied Human copied Human copied Human copied Human died Human died Human died Human died Human died Entry into pub *not* allowed for group {Man1, Boy1, Woman1}. Human copied Human copied Human copied Human died Human died Human died Entry into pub allowed for group {Man1, Woman1}. ---------- Human died Human died Human died

    56) RAII Technique of acquiring all resources (say allocation of memory) in constructor (of the classes) and
    releasing it (freeing memory) in destructor (of corresponding classes) is known as Resource Acquisition Is Initialisation (RAII).

    Practically, it means that we do not acquire/release resources in general code, but rather keep it embedded within an appropriate class.
    This will also mean that we avoid "naked" new/delete and keep them as part of some other constructor and destructor respectively.

    If the resource in the question is memory, above technique will avoid memory leak.

    57) Policy based design Certain parts of implementation may need to be kept flexible based on some aspects of the platform
    (e.g. processing speed, memory, type of peripherals, input/output devices, and so on).

    In our earlier example of "Creating template for a class", for implementing group, we used list from standard library.
    We could have used vector instead.

    Separating out such details in smaller classes is called "Policy based design" and these classes are known as policies.
    Below example shows two policies for storing the members, one with vector, and another with list.

    #include <iostream> #include <string> #include <vector> #include <list> class human { protected: std::string name; public: friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man() {} man(std::string ip_name) { name = ip_name; } }; class boy : public man { public: boy(std::string ip_name) { name = ip_name; } }; class woman : public human { public: woman() {} woman(std::string ip_name) { name = ip_name; } }; class girl : public woman { public: girl(std::string ip_name) { name = ip_name; } }; //Policy#1 - Store in vector template<typename T> struct vector_store { using item_type = T; std::vector<item_type*> storage; void add_item(item_type* item) { storage.push_back(item); } void print_items(void) { for(auto* item:storage) std::cout << *item << std::endl; } }; //Policy#2 - Store in list template<typename T> struct list_store { using item_type = T; std::list<item_type*> storage; void add_item(item_type* item) { storage.push_back(item); } void print_items(void) { for(auto* item:storage) std::cout << *item << std::endl; } }; template<typename store_policy> class group { private: store_policy store; public: void add_member(store_policy::item_type& item) { store.add_item(&item); } void print_group(void) { store.print_items(); } }; int main() { man Father("Father"); woman Mother("Mother"); boy Son("Son"); girl Daughter("Daughter"); group<vector_store<human>> vectorFamily; vectorFamily.add_member(Father); vectorFamily.add_member(Mother); vectorFamily.add_member(Son); vectorFamily.add_member(Daughter); std::cout << "vectorFamily includes .... " << std::endl; vectorFamily.print_group(); group<list_store<human>> listFamily; listFamily.add_member(Father); listFamily.add_member(Mother); listFamily.add_member(Son); listFamily.add_member(Daughter); std::cout << "listFamily includes .... " << std::endl; listFamily.print_group(); std::cout << "----------" << std::endl; return 0; }

    vectorFamily includes .... Father Mother Son Daughter listFamily includes .... Father Mother Son Daughter ----------
    58) Type checking with concept and requires In an example for Policy based design, both policies vector_store, and list_store will work only if type T supports operator <<.
    Instead of run-time failure, we can do this check at compile time with concept and requires.

    #include <iostream> #include <string> #include <vector> #include <list> class human { protected: std::string name; public: friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man() {} man(std::string ip_name) { name = ip_name; } }; class boy : public man { public: boy(std::string ip_name) { name = ip_name; } }; class woman : public human { public: woman() {} woman(std::string ip_name) { name = ip_name; } }; class girl : public woman { public: girl(std::string ip_name) { name = ip_name; } }; template <typename T> concept supports_cout = requires(T a) { std::cout << a; }; //Policy#1 - Store in vector template<typename T> requires supports_cout<T> struct vector_store { using item_type = T; std::vector<T*> storage; void add_item(T* item) { storage.push_back(item); } void print_items(void) { for(auto* item:storage) std::cout << *item << std::endl; } }; //Policy#2 - Store in list template<typename T> requires supports_cout<T> struct list_store { using item_type = T; std::list<T*> storage; void add_item(T* item) { storage.push_back(item); } void print_items(void) { for(auto* item:storage) std::cout << *item << std::endl; } }; template<typename store_policy> class group { private: store_policy store; public: void add_member(store_policy::item_type& item) { store.add_item(&item); } void print_group(void) { store.print_items(); } }; class mannequin { }; int main() { group<vector_store<human>> vectorFamily; group<list_store<human>> listFamily; group(vector_store<mannequin>> Dummies; std::cout << "----------" << std::endl; return 0; }

    example.cpp: In function ‘int main()’: example.cpp:112:22: error: template constraint failure for ‘template<class T> requires supports_cout<T> struct vector_store’

    59) Containers from standard library As of C++17,

    vector Variable size vector (single dimensional array)
    list Doubly-linked list
    forward_list Singly-linked list
    deque Double ended queue
    set Set (map with only key)
    multiset Value can occur multiple times
    map (Key,Value) array (binary tree implementation)
    multimap Key can occur multiple times
    unordered_map Hash array
    unordered_multimap Key can occur multiple times
    unordered_set Set with hash key
    unordered_multiset Key can occur multiple times

    For more details on each, you may refer en.cppreference.com, cplusplus.com or devdocs.io.

    60) Predicate (with find_if) Let us say, we want to iterate through a container, looking for the object that satisfy particular condition.
    This is possible with standard library algorithm find_if and such condition is known as a Predicate.

    #include <iostream> #include <string> #include <vector> class human { protected: std::string name; public: virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; int main() { std::vector<human*> mens_soccer_team; man Man1("Man1"); man Man2("Man2"); man Man3("Man3"); man Man4("Man4"); man Man5("Man5"); mens_soccer_team.push_back(&Man1); mens_soccer_team.push_back(&Man2); mens_soccer_team.push_back(&Man3); mens_soccer_team.push_back(&Man4); mens_soccer_team.push_back(&Man5); std::string looking_for = "Man4"; // Predicate with lamda expression auto find_man_lamda = std::find_if(mens_soccer_team.begin(), mens_soccer_team.end(), [looking_for](human* man_in_team) { if(man_in_team->get_name() == looking_for) return true; return false; } ); if(*find_man_lamda == nullptr) std::cout << "Lamda: Man4 *not* found." << std::endl; else std::cout << "Lamda: " << **find_man_lamda << " found." << std::endl; class find_if_man_functor { private: std::string find_name; public: find_if_man_functor(const std::string& ip_find_name) : find_name(ip_find_name) {} bool operator()(human* man_in_team) const { if(man_in_team->get_name() == find_name) return true; return false; } }; // Predicate with functor auto find_man_functor = std::find_if(mens_soccer_team.begin(), mens_soccer_team.end(), find_if_man_functor(looking_for)); if(*find_man_functor == nullptr) std::cout << "Functor: Man4 *not* found." << std::endl; else std::cout << "Functor: " << **find_man_functor << " found." << std::endl; std::cout << "----------" << std::endl; return 0; }

    Lamda: Man4 found. Functor: Man4 found. ----------

    61) Using random from standard library Below is random number generator template based on newer "Minimum standard" random engine.
    We used newer Minimal standard random generator (minstd_rand), others are mt19937, knuth_b, ranlux24_base, and so on.

    #include <iostream> #include <random> template <class T> class simple_integer_random_generator { private: unsigned int range_from; unsigned int range_to; T* p_generator; std::uniform_int_distribution<int>* p_distribution; public: simple_integer_random_generator(unsigned int ip_range_from, unsigned int ip_range_to) : range_from(ip_range_from), range_to(ip_range_to) { /* no checks for range_from and range_to */ std::random_device rd; //Seed p_generator = new T(rd()); p_distribution = new std::uniform_int_distribution<int>(range_from, range_to); } ~simple_integer_random_generator() { delete p_distribution; delete p_generator; } unsigned int get_rand(void) { return (*p_distribution)(*p_generator); } }; int main() { simple_integer_random_generator<std::minstd_rand> random_engine(1,100); unsigned int random_int; unsigned int how_many = 10; do { random_int = random_engine.get_rand(); std::cout << random_int << std::endl; --how_many; } while (how_many); std::cout << "----------" << std::endl; return 0; }

    78 69 82 6 85 26 80 99 74 84 ----------

    62) Alternatives example with variant Is it possible that function returns different types ? If yes, you may use variant.

    #include <iostream> #include <string> #include <variant> #include <random> class human { private: std::string name; public: human(std::string ip_name) { name = ip_name; std::cout << "Born" << std::endl; } ~human() { std::cout << "Died" << std::endl; } friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class bird { private: std::string name; public: bird(std::string ip_name) { name = ip_name; std::cout << "Born" << std::endl; } ~bird() { std::cout << "Died" << std::endl; } friend std::ostream& operator<<(std::ostream& out_stream, bird& ip_bird) { out_stream << ip_bird.name; return out_stream; } }; class fish { private: std::string name; public: fish(std::string ip_name) { name = ip_name; std::cout << "Born" << std::endl; } ~fish() { std::cout << "Died" << std::endl; } friend std::ostream& operator<<(std::ostream& out_stream, fish& ip_fish) { out_stream << ip_fish.name; return out_stream; } }; template <class T> class simple_integer_random_generator { private: unsigned int range_from; unsigned int range_to; T* p_generator; std::uniform_int_distribution<int>* p_distribution; public: simple_integer_random_generator(unsigned int ip_range_from, unsigned int ip_range_to) : range_from(ip_range_from), range_to(ip_range_to) { /* no checks for range_from and range_to */ std::random_device rd; //Seed p_generator = new T(rd()); p_distribution = new std::uniform_int_distribution<int>(range_from, range_to); } ~simple_integer_random_generator() { delete p_distribution; delete p_generator; } unsigned int get_rand(void) { return (*p_distribution)(*p_generator); } }; std::variant<human*, bird*, fish*> nature_factory(void) { static simple_integer_random_generator<std::minstd_rand> random_engine(1,3); switch(random_engine.get_rand()) { case 1: return new human("Human");break; case 2: return new bird("Bird");break; case 3: default: break; } return new fish("Fish"); } int main() { auto p_being = nature_factory(); if(std::holds_alternative<human*>(p_being)) { std::cout << "It is a " << *(std::get<human*>(p_being)) << std::endl; } else if(std::holds_alternative<bird*>(p_being)) { std::cout << "It is a " << *(std::get<bird*>(p_being)) << std::endl; } else if(std::holds_alternative<fish*>(p_being)) { std::cout << "It is a " << *(std::get<fish*>(p_being)) << std::endl; } // ensure to delete if(std::holds_alternative<human*>(p_being)) { delete (std::get<human*>(p_being)); } else if(std::holds_alternative<bird*>(p_being)) { delete (std::get<bird*>(p_being)); } else if(std::holds_alternative<fish*>(p_being)) { delete (std::get<fish*>(p_being)); } std::cout << "----------" << std::endl; return 0; }

    Born It is a Fish Died ----------

    63) Alternatives example with any Below example illustrate any and regular expressions

    #include <iostream> #include <string> #include <any> #include <random> #include <regex> class human { private: std::string name; public: human(std::string ip_name) { name = ip_name; std::cout << "Born" << std::endl; } ~human() { std::cout << "Died" << std::endl; } friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class bird { private: std::string name; public: bird(std::string ip_name) { name = ip_name; std::cout << "Born" << std::endl; } ~bird() { std::cout << "Died" << std::endl; } friend std::ostream& operator<<(std::ostream& out_stream, bird& ip_bird) { out_stream << ip_bird.name; return out_stream; } }; class fish { private: std::string name; public: fish(std::string ip_name) { name = ip_name; std::cout << "Born" << std::endl; } ~fish() { std::cout << "Died" << std::endl; } friend std::ostream& operator<<(std::ostream& out_stream, fish& ip_fish) { out_stream << ip_fish.name; return out_stream; } }; template <class T> class simple_integer_random_generator { private: unsigned int range_from; unsigned int range_to; T* p_generator; std::uniform_int_distribution<int>* p_distribution; public: simple_integer_random_generator(unsigned int ip_range_from, unsigned int ip_range_to) : range_from(ip_range_from), range_to(ip_range_to) { /* no checks for range_from and range_to */ std::random_device rd; //Seed p_generator = new T(rd()); p_distribution = new std::uniform_int_distribution<int>(range_from, range_to); } ~simple_integer_random_generator() { delete p_distribution; delete p_generator; } unsigned int get_rand(void) { return (*p_distribution)(*p_generator); } }; std::any nature_factory(void) { static simple_integer_random_generator<std::minstd_rand> random_engine(1,3); switch(random_engine.get_rand()) { case 1: return new human("Human");break; case 2: return new bird("Bird");break; case 3: default: break; } return new fish("Fish"); } int main() { auto p_being = nature_factory(); std::regex human_pattern {"human"}; std::regex bird_pattern {"bird"}; std::regex fish_pattern {"fish"}; if(std::regex_search(p_being.type().name(), human_pattern)) { std::cout << "It is a " << *(std::any_cast<human*>(p_being)) << std::endl; } else if(std::regex_search(p_being.type().name(), bird_pattern)) { std::cout << "It is a " << *(std::any_cast<bird*>(p_being)) << std::endl; } else if(std::regex_search(p_being.type().name(), fish_pattern)) { std::cout << "It is a " << *(std::any_cast<fish*>(p_being)) << std::endl; } // ensure to delete if(std::regex_search(p_being.type().name(), human_pattern)) { delete (std::any_cast<human*>(p_being)); } else if(std::regex_search(p_being.type().name(), bird_pattern)) { delete (std::any_cast<bird*>(p_being)); } else if(std::regex_search(p_being.type().name(), fish_pattern)) { delete (std::any_cast<fish*>(p_being)); } std::cout << "----------" << std::endl; return 0; }

    Born It is a Bird Died ----------

    64) Using polymorphic_allocator (C++17) new uses heap memory of object creation. C++17 introduced a way to use the concept of pool memory for dynamic object creation.

    Below example uses vector and list creation from a pool.
    There are additional traces to ensure that there is no memory leak.

    #include <iostream> #include <string> #include <vector> #include <list> #include <memory_resource> class human { protected: std::string name; public: human() { std::cout << "Born" << std::endl; } ~human() { std::cout << "Died" << std::endl; } friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man() {} man(std::string ip_name) { name = ip_name; } }; class boy : public man { public: boy(std::string ip_name) { name = ip_name; } }; class woman : public human { public: woman() {} woman(std::string ip_name) { name = ip_name; } }; class girl : public woman { public: girl(std::string ip_name) { name = ip_name; } }; //Policy#1 - Store in vector with pool template<typename IT, typename AT> struct vector_store_with_pool { using item_type = IT; using allocator_type = AT; std::vector<item_type*, allocator_type>* p_storage = nullptr; void create(allocator_type& allocator) { p_storage = new std::vector<item_type*, allocator_type>(allocator); std::cout << "create" << std::endl; } void destroy(void) { delete p_storage; std::cout << "destroy" << std::endl; } void add_item(item_type* item) { p_storage->push_back(item); } void print_items(void) { for(auto* item:*p_storage) std::cout << *item << std::endl; } }; //Policy#2 - Store in list with pool template<typename IT, typename AT> struct list_store_with_pool { using item_type = IT; using allocator_type = AT; std::list<item_type*, allocator_type>* p_storage = nullptr; void create(allocator_type& allocator) { p_storage = new std::list<item_type*, allocator_type>(allocator); std::cout << "create" << std::endl; } void destroy(void) { delete p_storage; std::cout << "destroy" << std::endl; } void add_item(item_type* item) { p_storage->push_back(item); } void print_items(void) { for(auto* item:*p_storage) std::cout << *item << std::endl; } }; template<typename store_policy> class group_with_pool { private: store_policy store; public: group_with_pool(store_policy::allocator_type& allocator) { store.create(allocator); } ~group_with_pool() { store.destroy(); } void add_member(store_policy::item_type& item) { store.add_item(&item); } void print_group(void) { store.print_items(); } }; int main() { man Father("Father"); woman Mother("Mother"); boy Son("Son"); girl Daughter("Daughter"); std::pmr::synchronized_pool_resource common_pool; std::pmr::polymorphic_allocator<human*> allocator(&common_pool); group_with_pool<vector_store_with_pool<human, std::pmr::polymorphic_allocator<human*>>> poolVectorFamily(allocator); poolVectorFamily.add_member(Father); poolVectorFamily.add_member(Mother); poolVectorFamily.add_member(Son); poolVectorFamily.add_member(Daughter); std::cout << "poolVectorFamily includes .... " << std::endl; poolVectorFamily.print_group(); group_with_pool<list_store_with_pool<human, std::pmr::polymorphic_allocator<human*>>> poolListFamily(allocator); poolListFamily.add_member(Father); poolListFamily.add_member(Mother); poolListFamily.add_member(Son); poolListFamily.add_member(Daughter); std::cout << "poolListFamily includes .... " << std::endl; poolListFamily.print_group(); std::cout << "----------" << std::endl; return 0; }

    Born Born Born Born create poolVectorFamily includes .... Father Mother Son Daughter create poolListFamily includes .... Father Mother Son Daughter ---------- destroy destroy Died Died Died Died

    65) Using for_each Example of map iterator rewritten with for_each.

    #include <iostream> #include <string> #include <map> class human { protected: std::string name; public: virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } void operator=(human& cp_human) = delete; }; class man : public human { public: man(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; int main() { man Customer1("Customer1"), Customer2("Customer2"), Customer3("Customer3"); std::map<std::string, unsigned int> restaurant_orders; unsigned int order_ctr = 0; restaurant_orders[Customer2.get_name()] = ++order_ctr; //1 restaurant_orders[Customer1.get_name()] = ++order_ctr; //2 restaurant_orders[Customer3.get_name()] = ++order_ctr; //3 std::map<std::string, unsigned int>::iterator index_to_orders; std::cout << "Iterating customer and their orders (using for_each and lamda expression) ..." << std::endl; for_each(restaurant_orders.begin(), restaurant_orders.end(), [](const std::pair<std::string, unsigned int>& first_second) { std::cout << "\t" << first_second.first << ", order# " << first_second.second << std::endl; } ); std::cout << "----------" << std::endl; return 0; }

    Iterating customer and their orders (using for_each and lamda expression) ... Customer1, order# 2 Customer2, order# 1 Customer3, order# 3 ----------

    66) thread and mutex Example of thread and mutex with a call to an object.
    It is *not* necessary that print_thread_LIFO will be called always before print_thread_FIFO.

    #include <iostream> #include <string> #include <list> #include <thread> #include <mutex> class human { protected: std::string name; public: friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name) { name = ip_name; } }; template<typename T> class group { private: std::list<T*> *members; public: group() { members = new std::list<T*>; } ~group() { delete members; } void add_member(T& person) { auto member_iterator = members->begin(); members->insert(member_iterator, &person); } void print_group_LIFO(std::mutex* p_print_lock) { if(members == nullptr) return; p_print_lock->lock(); std::cout << "Soccer team LIFO:" << std::endl; for(auto member_iterator = members->begin(); member_iterator != members->end(); ++member_iterator) { T* member = *member_iterator; std::cout << *member << std::endl; } p_print_lock->unlock(); } void print_group_FIFO(std::mutex* p_print_lock) { if(members == nullptr) return; p_print_lock->lock(); std::cout << "Soccer team FIFO:" << std::endl; for(auto reverse_member_iterator = members->rbegin(); reverse_member_iterator != members->rend(); ++reverse_member_iterator) { T* member = *reverse_member_iterator; std::cout << *member << std::endl; } p_print_lock->unlock(); } void remove_member(T& person) { members->remove(&person); } }; using mens_group = group<man>; int main() { mens_group mens_soccer_team; man Man1("Man1"); man Man2("Man2"); man Man3("Man3"); man Man4("Man4"); mens_soccer_team.add_member(Man1); mens_soccer_team.add_member(Man2); mens_soccer_team.add_member(Man3); mens_soccer_team.add_member(Man4); std::mutex print_lock; std::thread print_thread_LIFO ( &mens_group::print_group_LIFO, &mens_soccer_team, &print_lock ); std::thread print_thread_FIFO ( &mens_group::print_group_FIFO, &mens_soccer_team, &print_lock ); print_thread_LIFO.join(); print_thread_FIFO.join(); std::cout << "----------" << std::endl; return 0; }

    Soccer team LIFO: Man4 Man3 Man2 Man1 Soccer team FIFO: Man1 Man2 Man3 Man4 ----------

    67) Another example of thread and mutex This is one possible way to implement communication between two threads.

    We have also used chrono from standard library.

    #include <iostream> #include <string> #include <any> #include <random> #include <regex> #include <thread> #include <chrono> class human { private: std::string name; static unsigned int population; public: human(std::string ip_name) { name = ip_name; ++population; //std::cout << "Born" << std::endl; } ~human() { //std::cout << "Died" << std::endl; } friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } static unsigned int get_population(void) { return population; } }; unsigned int human::population = 0; class bird { private: std::string name; static unsigned int population; public: bird(std::string ip_name) { name = ip_name; ++population; //std::cout << "Born" << std::endl; } ~bird() { //std::cout << "Died" << std::endl; } friend std::ostream& operator<<(std::ostream& out_stream, bird& ip_bird) { out_stream << ip_bird.name; return out_stream; } static unsigned int get_population(void) { return population; } }; unsigned int bird::population = 0; class fish { private: std::string name; static unsigned int population; public: fish(std::string ip_name) { name = ip_name; ++population; //std::cout << "Born" << std::endl; } ~fish() { //std::cout << "Died" << std::endl; } friend std::ostream& operator<<(std::ostream& out_stream, fish& ip_fish) { out_stream << ip_fish.name; return out_stream; } static unsigned int get_population(void) { return population; } }; unsigned int fish::population = 0; template <class T> class simple_integer_random_generator { private: unsigned int range_from; unsigned int range_to; T* p_generator; std::uniform_int_distribution<int>* p_distribution; public: simple_integer_random_generator(unsigned int ip_range_from, unsigned int ip_range_to) : range_from(ip_range_from), range_to(ip_range_to) { /* no checks for range_from and range_to */ std::random_device rd; //Seed p_generator = new T(rd()); p_distribution = new std::uniform_int_distribution<int>(range_from, range_to); } ~simple_integer_random_generator() { delete p_distribution; delete p_generator; } unsigned int get_rand(void) { return (*p_distribution)(*p_generator); } }; std::any nature_factory(void) { static simple_integer_random_generator<std::minstd_rand> random_engine(1,3); switch(random_engine.get_rand()) { case 1: return new human("Human");break; case 2: return new bird("Bird");break; case 3: default: break; } return new fish("Fish"); } enum class flag_type { free, nature_in_progress, population_consensus_in_progress }; struct sync_lock_type { std::mutex mutex_lock; flag_type flag ; }; void run_nature_factory(unsigned int time_microseconds, sync_lock_type* p_sync_lock) { auto time_start = std::chrono::high_resolution_clock::now(); auto time_check = std::chrono::high_resolution_clock::now(); static std::vector<human*> human_world; static std::vector<bird*> bird_world; static std::vector<fish*> fish_world; const static std::regex human_pattern {"human"}; const static std::regex bird_pattern {"bird"}; const static std::regex fish_pattern {"fish"}; bool go_ahead = false; do { go_ahead = false; p_sync_lock->mutex_lock.lock(); if(p_sync_lock->flag != flag_type::population_consensus_in_progress) { p_sync_lock->flag = flag_type::nature_in_progress; go_ahead = true; } p_sync_lock->mutex_lock.unlock(); if(go_ahead) { auto p_being = nature_factory(); if(std::regex_search(p_being.type().name(), human_pattern)) { std::cout << "It is a " << *(std::any_cast<human*>(p_being)) << std::endl; human_world.push_back(std::any_cast<human*>(p_being)); } else if(std::regex_search(p_being.type().name(), bird_pattern)) { std::cout << "It is a " << *(std::any_cast<bird*>(p_being)) << std::endl; bird_world.push_back(std::any_cast<bird*>(p_being)); } else if(std::regex_search(p_being.type().name(), fish_pattern)) { std::cout << "It is a " << *(std::any_cast<fish*>(p_being)) << std::endl; fish_world.push_back(std::any_cast<fish*>(p_being)); } p_sync_lock->mutex_lock.lock(); p_sync_lock->flag = flag_type::free; p_sync_lock->mutex_lock.unlock(); } time_check = std::chrono::high_resolution_clock::now(); } while( std::chrono::duration_cast<std::chrono::microseconds>(time_check - time_start).count() < time_microseconds ); go_ahead = false; do { p_sync_lock->mutex_lock.lock(); if(p_sync_lock->flag != flag_type::population_consensus_in_progress) { p_sync_lock->flag = flag_type::nature_in_progress; go_ahead = true; } p_sync_lock->mutex_lock.unlock(); } while(go_ahead == false); for(auto p_human:human_world) { delete p_human; } for(auto p_bird:bird_world) { delete p_bird; } for(auto p_fish:fish_world) { delete p_fish; } p_sync_lock->mutex_lock.lock(); p_sync_lock->flag = flag_type::free; p_sync_lock->mutex_lock.unlock(); } void population_consensus(unsigned int time_microseconds, sync_lock_type* p_sync_lock, unsigned int break_period) { auto time_start = std::chrono::high_resolution_clock::now(); auto time_check = std::chrono::high_resolution_clock::now(); unsigned int human_population; unsigned int bird_population; unsigned int fish_population; bool go_ahead = false; do { go_ahead = false; p_sync_lock->mutex_lock.lock(); if(p_sync_lock->flag != flag_type::nature_in_progress) { p_sync_lock->flag = flag_type::population_consensus_in_progress; go_ahead = true; } p_sync_lock->mutex_lock.unlock(); if(go_ahead) { human_population = human::get_population(); bird_population = bird::get_population(); fish_population = fish::get_population(); std::cout << "Human(" << human_population << "), Bird(" << bird_population << "), Fish(" << fish_population << ")" << std::endl; p_sync_lock->mutex_lock.lock(); p_sync_lock->flag = flag_type::free; p_sync_lock->mutex_lock.unlock(); std::this_thread::sleep_for(std::chrono::microseconds{break_period}); } time_check = std::chrono::high_resolution_clock::now(); } while( std::chrono::duration_cast<std::chrono::microseconds>(time_check - time_start).count() < time_microseconds ); } int main() { const unsigned int one_life = 1000000; const unsigned int consensus_break_period = 1000; sync_lock_type sync_lock; std::thread life_cycle(run_nature_factory, one_life, &sync_lock); std::thread population_check(population_consensus, one_life, &sync_lock, consensus_break_period); life_cycle.join(); population_check.join(); std::cout << "----------" << std::endl; return 0; }

    Human(0), Bird(0), Fish(0) It is a Human It is a Human It is a Human It is a Fish It is a Human It is a Bird It is a Bird It is a Bird Human(4), Bird(3), Fish(1) It is a Bird It is a Human ... It is a Human It is a Bird Human(2088), Bird(2106), Fish(2102) It is a Human It is a Bird It is a Bird It is a Fish It is a Bird It is a Bird ----------

    68) thread_local Bjarne - "A thread_local resembles a local variable, but a local variable has its lifetime and access limited by its scope within a function,
    whereas a thread_local is shared among all functions of a thread and ‘‘lives’’ for as long as the thread."

    It makes sense that thread_local is usually applied to static variables.
    However, we need to be sure of is this what we want.

    Without thread_local

    #include <iostream> #include <thread> #include <mutex> class human { private: static int population_ctr; public: human() { ++population_ctr; } ~human() { --population_ctr; } static int population(void) { return population_ctr; } }; int human::population_ctr = 0; class man : public human { public: man() {} ~man() {} }; void generate_men(unsigned short how_many, std::mutex* p_print_lock) { while(how_many--) { man temp_man; } p_print_lock->lock(); std::cout << "Population is " << human::population() << std::endl; p_print_lock->unlock(); }; int main() { std::mutex print_lock; std::thread thread1(generate_men, 100000, &print_lock); std::thread thread2(generate_men, 100000, &print_lock); thread1.join(); thread2.join(); std::cout << "----------" << std::endl; return 0; }

    ~/C++$ ./a.out Population is 2 Population is 1 ---------- ~/C++$ ./a.out Population is 1 Population is 1 ---------- ~/C++$ ./a.out Population is 0 Population is 0


    With thread_local

    #include <iostream> #include <thread> #include <mutex> class human { private: thread_local static int population_ctr; public: human() { ++population_ctr; } ~human() { --population_ctr; } static int population(void) { return population_ctr; } }; thread_local int human::population_ctr = 0; class man : public human { public: man() {} ~man() {} }; void generate_men(unsigned short how_many, std::mutex* p_print_lock) { while(how_many--) { man temp_man; } p_print_lock->lock(); std::cout << "Population is " << human::population() << std::endl; p_print_lock->unlock(); }; int main() { std::mutex print_lock; std::thread thread1(generate_men, 100000, &print_lock); std::thread thread2(generate_men, 100000, &print_lock); thread1.join(); thread2.join(); std::cout << "----------" << std::endl; return 0; }

    ~/C++$ ./a.out Population is 0 Population is 0 ---------- ~/C++$ ./a.out Population is 0 Population is 0 ---------- ~/C++$ ./a.out Population is 0 Population is 0 ----------

    69) Automatic template argument deduction (C++17) Sometimes compiler can deduce template argument from the constructor arguments as shown in below example.

    Example also shows usage of initializer_list.

    #include <iostream> #include <string> #include <list> #include <vector> class human { protected: std::string name; public: virtual std::string get_name(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; class woman : public human { public: woman(std::string ip_name) { name = ip_name; } std::string get_name(void) { return name; } }; template<typename T> class group { private: std::list<T*> *members; public: group() { members = new std::list<T*>; } group(std::initializer_list<T*> ip_list) { members = new std::list<T*>; for(auto ip_member:ip_list) { add_member(*ip_member); } } ~group() { delete members; } void add_member(T& person) { auto member_iterator = members->begin(); members->insert(member_iterator, &person); } void print_group(void) { if(members == nullptr) return; for(auto member_iterator = members->begin(); member_iterator != members->end(); ++member_iterator) { T* member = *member_iterator; std::cout << *member << std::endl; } } void remove_member(T& person) { members->remove(&person); } }; int main() { man* Man1 = new man("Man1"); man* Man2 = new man("Man2"); group<man> mens_soccer_team{Man1, Man2}; //template argument explicitly mentioned std::cout << "Soccer team:" << std::endl; mens_soccer_team.print_group(); woman* Woman1 = new woman("Woman1"); woman* Woman2 = new woman("Woman2"); group womens_kitty_group{Woman1, Woman2}; //template argument deduction std::cout << "Kitty group:" << std::endl; womens_kitty_group.print_group(); //clean-up delete Man1; delete Man2; delete Woman1; delete Woman2; std::cout << "----------" << std::endl; return 0; }

    Soccer team: Man2 Man1 Kitty group: Woman2 Woman1 ----------

    70) Template argument deduction guide (C++17) If the constructor arguments are *not* sufficient to deduce the template argument (type), a guide can be provided.

    "if you come across group of (iter,iter), please map it to group of iter's value type"

    #include <iostream> #include <string> #include <list> #include <vector> class human { protected: std::string name; public: friend std::ostream& operator<<(std::ostream& out_stream, human& ip_human) { out_stream << ip_human.name; return out_stream; } }; class man : public human { public: man(std::string ip_name) { name = ip_name; } }; class woman : public human { public: woman(std::string ip_name) { name = ip_name; } }; template<typename TP> class group { private: std::list<TP> *members; public: group() { members = new std::list<TP>; } group(std::initializer_list<TP> ip_list) { members = new std::list<TP>; for(auto ip_member:ip_list) { add_member(ip_member); } } template<typename iter> group(iter iterator_begin, iter iterator_end) { members = new std::list<TP>; for(iter local_iterator = iterator_begin; local_iterator != iterator_end; ++local_iterator) { add_member(*local_iterator); } } ~group() { delete members; } void add_member(TP person) { auto member_iterator = members->begin(); members->insert(member_iterator, person); } void print_group(void) { if(members == nullptr) return; for(auto member_iterator = members->begin(); member_iterator != members->end(); ++member_iterator) { TP member = *member_iterator; std::cout << *member << std::endl; } } void remove_member(TP person) { members->remove(person); } }; // template argument deduction guide // if you come across group of (iter,iter), please map it to group of iter's value type template<typename iter> group(iter iterator_begin, iter iterator_end) -> group<typename iter::value_type>; int main() { man* Man1 = new man("Man1"); man* Man2 = new man("Man2"); group<man*> mens_soccer_team{Man1, Man2}; //template argument explicitly mentioned std::cout << "Soccer team:" << std::endl; mens_soccer_team.print_group(); woman* Woman1 = new woman("Woman1"); woman* Woman2 = new woman("Woman2"); group womens_kitty_group{Woman1, Woman2}; //template argument deduction std::cout << "Kitty group:" << std::endl; womens_kitty_group.print_group(); woman* Woman3 = new woman("Woman3"); woman* Woman4 = new woman("Woman4"); std::vector<woman*> new_residents{Woman3, Woman4}; // argument deduction using user provided guide group new_womens_kitty_group(new_residents.begin(), new_residents.end()); std::cout << "New Kitty group:" << std::endl; new_womens_kitty_group.print_group(); //clean-up delete Man1; delete Man2; delete Woman1; delete Woman2; delete Woman3; delete Woman4; std::cout << "----------" << std::endl; return 0; }

    Soccer team: Man2 Man1 Kitty group: Woman2 Woman1 New Kitty group: Woman4 Woman3 ----------

    71) decltype, typeid Below is simple illustration of decltype, typeid, and operator+ overloading.

    #include <iostream> class man { public: man() {} }; class spider { public: spider() {} }; class bat_costume { public: bat_costume() {} }; class superhero { public: superhero() {} }; template<typename T, typename U> auto operator+(const T& a, const U& b) -> decltype(superhero{}); // template argument deduction guide in declaration template<typename T, typename U> auto operator+(const T& a, const U& b) -> decltype(superhero{}) // must specify it again in definition { superhero superhero_born; std::cout << "Superhero born from '" << typeid(a).name() << "' and '" << typeid(b).name() << "'" << std::endl; return superhero_born; } int main() { man A_normal_guy; spider A_mystry_spider; decltype(A_normal_guy + A_mystry_spider) A_Spiderman = A_normal_guy + A_mystry_spider; man A_rich_guy; bat_costume A_bat_costume; auto A_Batman = A_rich_guy + A_bat_costume; // we could use "decltype(man{} + bat_costume{})" or "decltype(A_rich_guy + A_bat_costume)" instead of "auto" std::cout << "----------" << std::endl; return 0; }

    Superhero born from '3man' and '6spider' Superhero born from '3man' and '11bat_costume' ----------

    72) decltype(auto) (C++14) decltype example can be rewritten with decltype(auto) or simply with auto.

    With decltype(auto)

    #include <iostream> class man { public: man() {} }; class spider { public: spider() {} }; class bat_costume { public: bat_costume() {} }; class superhero { public: superhero() {} }; template<typename T, typename U> decltype(auto) operator+(const T& a, const U& b); template<typename T, typename U> decltype(auto) operator+(const T& a, const U& b) { superhero superhero_born; std::cout << "Superhero born from '" << typeid(a).name() << "' and '" << typeid(b).name() << "'" << std::endl; return superhero_born; } int main() { man A_normal_guy; spider A_mystry_spider; decltype(auto) A_Spiderman = A_normal_guy + A_mystry_spider; man A_rich_guy; bat_costume A_bat_costume; auto A_Batman = A_rich_guy + A_bat_costume; std::cout << "----------" << std::endl; return 0; }

    Superhero born from '3man' and '6spider' Superhero born from '3man' and '11bat_costume' ----------


    With auto

    #include <iostream> class man { public: man() {} }; class spider { public: spider() {} }; class bat_costume { public: bat_costume() {} }; class superhero { public: superhero() {} }; template<typename T, typename U> auto operator+(const T& a, const U& b); template<typename T, typename U> auto operator+(const T& a, const U& b) { superhero superhero_born; std::cout << "Superhero born from '" << typeid(a).name() << "' and '" << typeid(b).name() << "'" << std::endl; return superhero_born; } int main() { man A_normal_guy; spider A_mystry_spider; auto A_Spiderman = A_normal_guy + A_mystry_spider; man A_rich_guy; bat_costume A_bat_costume; auto A_Batman = A_rich_guy + A_bat_costume; std::cout << "----------" << std::endl; return 0; }

    Superhero born from '3man' and '6spider' Superhero born from '3man' and '11bat_costume' ----------

    73) auto versus decltype(auto) Below example illustrate difference of behaviour between auto versus decltype(auto).

    #include <iostream> #include <string> enum class emotion_type { HAPPY, OVERJOYED }; std::ostream& operator<<(std::ostream& out_stream, emotion_type emotion) { switch(emotion) { case emotion_type::HAPPY: out_stream << "Happy"; break; case emotion_type::OVERJOYED: out_stream << "Overjoyed"; break; default: out_stream << "<unknown>"; break; } return out_stream; } enum class aptitude_type { DREAMER, ACHIEVER }; std::ostream& operator<<(std::ostream& out_stream, aptitude_type aptitude) { switch(aptitude) { case aptitude_type::DREAMER: out_stream << "Dreamer"; break; case aptitude_type::ACHIEVER: out_stream << "Achiever"; break; default: out_stream << "<unknown>"; break; } return out_stream; } class human { private: emotion_type my_emotion = emotion_type::HAPPY; aptitude_type my_aptitude = aptitude_type::DREAMER; public: emotion_type& emotion(void) { return my_emotion; } const aptitude_type& aptitude(void) { return my_aptitude; } decltype(auto) get_emotion(void) { return my_emotion; } decltype(auto) get_aptitude(void) { return (my_aptitude); // brackets around return (variable) name changes type } }; int main() { human Human; auto emotion = Human.emotion(); // emotion will be of type "emotion_type" std::cout << Human.emotion() << std::endl; emotion = emotion_type::OVERJOYED; std::cout << Human.emotion() << std::endl; std::cout << "----------" << std::endl; decltype(auto) emotion2 = Human.emotion(); // emotion2 will be of type "emotion_type&" std::cout << Human.emotion() << std::endl; emotion2 = emotion_type::OVERJOYED; std::cout << Human.emotion() << std::endl; std::cout << "----------" << std::endl; auto aptitude = Human.aptitude(); // aptitude will be of type "aptitude_type" std::cout << Human.aptitude() << std::endl; aptitude = aptitude_type::ACHIEVER; std::cout << Human.aptitude() << std::endl; std::cout << "----------" << std::endl; decltype(auto) aptitude2 = Human.aptitude(); // aptitude2 will be of type "const aptitude_type&" /* below statement will raise compiler error "error: assignment of read-only reference ‘aptitude2’" aptitude2 = aptitude_type::ACHIEVER; */ std::cout << "----------" << std::endl; decltype(auto) emotion3 = Human.get_emotion(); // emotion will be of type "emotion_type" std::cout << Human.emotion() << std::endl; emotion3 = emotion_type::OVERJOYED; std::cout << Human.emotion() << std::endl; std::cout << "----------" << std::endl; decltype(auto) aptitude3 = Human.get_aptitude(); // aptitude will be of type "aptitude_type&" std::cout << Human.aptitude() << std::endl; aptitude3 = aptitude_type::ACHIEVER; std::cout << Human.aptitude() << std::endl; std::cout << "----------" << std::endl; return 0; }

    Happy Happy ---------- Happy Overjoyed ---------- Dreamer Dreamer ---------- ---------- Overjoyed Overjoyed ---------- Dreamer Achiever ----------

    74) Attribute [[noreturn]] [[ ]] is called an attribute.
    Below is an example of [[noreturn]].
    Another attribute is [[carries_dependency]] - relevant to memory model.

    #include <iostream> #include <string> class human { protected: std::string name; public: ~human() { std::cout << "Died" << std::endl; } }; class man : public human { public: man(std::string ip_name) { name = ip_name; } }; [[noreturn]] void black_hole(human* p_human) { delete p_human; std::exit(1); } int main() { man* Man1 = new man("Man1"); black_hole(Man1); delete(Man1); std::cout << "----------" << std::endl; return 0; }

    Died

    75) Attribute [[deprecated]] (C++14) As the word suggests, idea is to warn the users that the function is obsolete and it is to be avoided.

    Compiler will print a warning if such function is called.

    #include <iostream> class human { public: [[deprecated]] void work_70_hours_per_week(void) {} }; int main() { human Worker; Worker.work_70_hours_per_week(); std::cout << "----------" << std::endl; return 0; }

    example.cpp: In function ‘int main()’: example.cpp:13:32: warning: ‘void human::work_70_hours_per_week()’ is deprecated [-Wdeprecated-declarations]

    76) Structured binding (C++17) Bjarne = "The mechanism for giving local names to members of a class object is called structured binding".

    #include <iostream> #include <string> #include <map> struct record_type; class human { public: enum class profession_type { person, student, teacher, engineer, businessman }; virtual record_type get_record(void) = 0; friend std::ostream& operator<<(std::ostream& out_stream, profession_type profession) { std::string profession_str; switch(profession) { default: case profession_type::person: profession_str = "Person"; break; case profession_type::student: profession_str = "Student"; break; case profession_type::teacher: profession_str = "Teacher"; break; case profession_type::engineer: profession_str = "Engineer"; break; case profession_type::businessman: profession_str = "Businessman"; break; } out_stream << profession_str; return out_stream; } protected: std::string name; profession_type profession; }; struct record_type { std::string name; human::profession_type profession; }; class man : public human { public: man(std::string ip_name, human::profession_type ip_profession) { name = ip_name; profession = ip_profession; } record_type get_record(void) { return {name, profession}; } }; int main() { man Man1("Man1", human::profession_type::engineer); auto record = Man1.get_record(); std::cout << record.name << " is " << record.profession << "." << std::endl; man Man2("Man2", human::profession_type::student); auto [name2, profession2] = Man2.get_record(); // structured binding std::cout << name2 << " is " << profession2 << "." << std::endl; auto [name1, profession1 ] = record; // structured binding std::map<std::string, human::profession_type> record_map { { name1, profession1 }, { name2, profession2 } }; for( auto [key, value] : record_map ) // structured binding { std::cout << key << " is " << value << "." << std::endl; } std::cout << "----------" << std::endl; return 0; }

    Man1 is Engineer. Man2 is Student. Man1 is Engineer. Man2 is Student. ----------

    77) Attribute [[fallthrough]] (C++17) As the name suggests, [[fallthrough]] is useful in switch case statement.

    #include <iostream> #include <string> #include <vector> class human { public: enum class profession_type { person, student, teacher, engineer, businessman }; protected: unsigned short age; std::string name; profession_type profession; }; class man : public human { public: man(std::string ip_name, human::profession_type ip_profession, unsigned short ip_age) { name = ip_name; profession = ip_profession; age = ip_age; } std::string get_name() { return name; } profession_type get_profession() { return profession; } unsigned short get_age() { return age; } }; int main() { man Man1("Jack", human::profession_type::engineer, 32); man Man2("John", human::profession_type::student, 18); man Man3("Doe", human::profession_type::student, 18); man Man4("Chris", human::profession_type::teacher, 40); std::vector<man*> candidates; candidates.push_back(&Man1); candidates.push_back(&Man2); candidates.push_back(&Man3); candidates.push_back(&Man4); // looking for student of age 18, but not named 'Doe' for(auto candidate:candidates) { switch(candidate->get_profession()) { case human::profession_type::student: { if(candidate->get_name() == "Doe") { [[fallthrough]]; } else if(candidate->get_age() == 18) { std::cout << "Got it, his name is " << candidate->get_name() << std::endl; break; } } default: { std::cout << candidate->get_name() << " - no match " << std::endl; } } } std::cout << "----------" << std::endl; return 0; }

    Jack - no match Got it, his name is John Doe - no match Chris - no match ----------

    78) Generalised or Nontrivial union union is said to be nontrivial when one it its member is a class with constructors/destructor, like in the example below.
    C++ has set some conditions on such union (due to its nature).
    One notable condition is union (or class containing it) must explicitly define constructor and destructor.
    Please refer "The C++ Programming Language (4th edition) by Bjarne Stroustrup", chapter 8.3 for more details.

    #include <iostream> #include <vector> class man { public: std::string name; }; class woman { public: std::string name; }; class employee { public: enum class gender_t { male, female }; // nontrivial union union { man Man; woman Woman; }; gender_t gender; employee() // mandatory constructor { std::cout << "employee()" << std::endl; } ~employee() // mandatory destructor { std::cout << "~employee()" << std::endl; } void operator=(const man& ip_man) { Man = ip_man; gender = gender_t::male; } void operator=(const woman& ip_woman) { Woman = ip_woman; gender = gender_t::female; } friend std::ostream& operator<<(std::ostream& out_stream, employee& ip_employee) { switch(ip_employee.gender) { case gender_t::male: out_stream << ip_employee.Man.name; break; case gender_t::female: out_stream << ip_employee.Woman.name; break; default: break; } return out_stream; } }; int main() { man Man1; woman Woman1; Man1.name = "Man1"; Woman1.name = "Woman1"; std::vector<employee*> Employees; employee Employee1; employee Employee2; Employee1 = Man1; Employee2 = Woman1; Employees.push_back(&Employee1); Employees.push_back(&Employee2); std::cout << "Employees are ... " << std::endl; for(auto employee_iterator:Employees) std::cout << *employee_iterator << std::endl; std::cout << "----------" << std::endl; return 0; }

    employee() employee() Employees are ... Man1 Woman1 ---------- ~employee() ~employee()

    79) Unicode string literal In C++17 (should work in previous versions as well)

    #include <iostream> int main() { // Unicode literal in UTF-8 const char* Devanagiri_script_characters = u8"\u0905, \u0906, \u0907, and \u0908."; std::cout << "First 4 letters of Devanagiri script are: " << std::endl; std::cout << Devanagiri_script_characters << std::endl; std::cout << "----------" << std::endl; return 0; }

    First 4 letters of Devanagiri script are: अ, आ, इ, and ई. ----------

    In C++20

    #include <iostream> int main() { // Unicode literal in UTF-8 const char8_t* Devanagiri_script_characters = u8"\u0905, \u0906, \u0907, and \u0908."; std::cout << "First 4 letters of Devanagiri script are: " << std::endl; std::cout << reinterpret_cast<const char*>(Devanagiri_script_characters) << std::endl; std::cout << "----------" << std::endl; return 0; }

    First 4 letters of Devanagiri script are: अ, आ, इ, and ई. ----------

    80) User defined literal With operator"", we can define our own literals.

    #include <iostream> enum class feeling_type { content, bored, happy, sad }; feeling_type operator ""_feeling(const char* f, size_t n) { std::string feeling = std::string{f,n}; if(feeling == "bored") return feeling_type::bored; if(feeling == "happy") return feeling_type::happy; if(feeling == "sad") return feeling_type::sad; return feeling_type::content; } int main() { // user defined literal feeling_type feeling = "content"_feeling; switch(feeling) { case feeling_type::content: std::cout << "Finally, a 'content' feeling." << std::endl; break; case feeling_type::happy: std::cout << "Best feeling of being 'happy'." << std::endl; break; case feeling_type::sad: std::cout << "Don't be 'sad'." << std::endl; break; case feeling_type::bored: default: std::cout << "Why so 'bored' ?" << std::endl; break; } std::cout << "----------" << std::endl; return 0; }

    Finally, a 'content' feeling. ----------

    81) Concept of "value"
    lvalue e.g. int integer;
    rvalue e.g. int* ptr_integer;
    lvalue reference e.g. void update_integer(int& integer);
    rvalue reference e.g. void update_integer_list(int&& list_integer);


    82) Member function's reference qualifier With reference qualifier, member function call can be controlled to be on lvalue reference or rvalue reference.

    #include <iostream> #include <string> class worker { private: std::string name; public: worker(std::string ip_name) : name(ip_name) { std::cout << "worker(" << name << ")" << std::endl; } void do_the_job(void) & // lvalue reference { std::cout << "do_the_job() lvalue reference" << std::endl; } void do_the_job(void) && // rvalue reference { std::cout << "do_the_job() rvalue reference" << std::endl; } ~worker() { std::cout << "~worker(" << name << ")" << std::endl; } }; worker temporary_worker_factory(std::string ip_name) { return *(new worker(ip_name)); } int main() { worker Worker("Worker"); Worker.do_the_job(); temporary_worker_factory("Temp").do_the_job(); std::cout << "----------" << std::endl; return 0; }

    worker(Worker) do_the_job() lvalue reference worker(Temp) do_the_job() rvalue reference ~worker(Temp) ---------- ~worker(Worker)

    83) Glossary
    202002L - 1
    Unicode literal - 79, 79
    __cplusplus - 1
    aliases - 49
    alien - 50
    any - 63
    any_cast - 63
    assignment operator - 23
    attribute noreturn - 74
    auto - 25, 72, 72, 73
    back_inserter - 34
    begin - 26
    catch - 35
    cbegin - 26
    cend - 26
    chrono - 67
    concept - 51, 58
    const - 38
    const_iterator - 26
    constexpr - 39, 40
    constructor - 6, 14
    copy - 32, 34
    copy constructor - 23, 33
    decltype - 71, 72, 72, 73
    delegating constructor - 16
    delete - 24
    deprecated - 75
    destructor - 6
    dynamic_cast - 27
    end - 26
    enum class - 37
    error_no_list - 35
    fallthrough - 77
    final - 42
    find_if - 60
    first - 26
    fold expression - 53
    for_each - 65
    forward - 54
    forwarding constructor - 16
    friend - 22
    function - 21
    functional - 21
    functor - 60
    gender_t - 37
    get - 62
    group - 29
    high_resolution_clock - 67
    holds_alternative - 62
    human - 10
    in-class member initialiser - 16
    inheriting constructors - 17
    initialisation with {} - 15
    initializer_list - 69
    is_assignable - 48
    iterator - 26
    join - 66
    lamda expression - 60
    list - 29
    list_store - 57
    lock - 28, 66, 67
    lvalue reference - 32, 54, 82
    make_move_iterator - 34
    man - 10
    map - 26, 26
    memory - 28
    memory_resource - 64
    mens_group - 49
    microseconds - 67
    minstd_rand - 61
    more_than_ref_height - 44, 45
    more_than_ref_weight - 44, 45
    move - 32, 33
    move constructor - 33
    move_iterator - 34
    multiple inheritance - 11
    mutex - 66, 67
    namespace - 5, 7, 7
    next - 26
    noexcept - 36, 36
    nontrivial - 78
    noreturn - 74
    now - 67
    nullptr - 10
    operator() - 44
    operator+ - 71
    operator<< - 22, 22
    operator= - 24
    override - 41, 41
    pmr - 64
    polymorphic_allocator - 64
    predicate - 60
    prev - 26
    protected - 13
    pub_entry_allowed - 52
    random - 61
    rbegin - 26
    ref_measurement - 44, 45
    regex - 63
    regex_search - 63
    rend - 26
    requires - 51, 51, 58
    return by reference - 18
    reverse_iterator - 26
    rvalue reference - 32, 54, 82
    second - 26
    shared_ptr - 28
    size - 25
    static - 12
    static_assert - 48
    store_policy - 57
    string - 20
    structured binding - 76
    supports_cout - 58
    synchronized_pool_resource - 64
    template - 29, 31, 45
    template argument deduction - 69
    template argument deduction guide - 70, 71
    template specialisation - 31
    thread - 66, 67
    thread_local - 68, 68
    throw - 35
    try - 35
    typeid - 71
    union - 78
    unique_ptr - 28
    unlock - 66, 67
    user defined literal - 80
    using - 5, 5, 7, 7, 7, 17, 49, 57
    variable template - 30
    variadic - 52
    variant - 62, 62
    vector - 25
    vector_store - 57
    virtual - 19, 20
    weak_ptr - 28
    woman - 10
    womens_group - 49



    © Copyright Samir Amberkar 2023-24