C++


Creative Commons License
This -C++- tutorial is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License
Preamble
This tutorial is about key features of C++. Please note that some features are supported from C++11, C++14, C++17 or, C++20 only. You may also look at this blog or this other one, which sum up the key novelties brought out from C++11.
Headlines
In C++, primitive types are (bool with false and true as possible values), char, wchar_t, char16_t, char32_t, short (at least 16-bit long), int (and variants), long (at least 32-bit long), long long (at least 64-bit long), float, double and long double.
Rule(s)
Example
assert(sizeof(long) == 8); // 64-bit Windows OS
// Access to 'SHRT_MAX' or 'SHRT_MIN' requires '#include <climits>'
std::cout << "short: " << sizeof (short) << '\n'; // '2' is displayed
std::cout << '\n' << "'SHRT_MAX': " << SHRT_MAX << '\n' // '32767' is displayed
    << "'SHRT_MIN': " << SHRT_MIN << '\n'; // '-32768' is displayed
See also

Numbers representation

Rule(s)
Example (short integers) Numbers.Cpp.zip 
#include <bitset>
#include <climits> // 'CHAR_BIT', SHRT_MAX'...
…
std::bitset<sizeof (short) * CHAR_BIT > one(1); // How many bits in a byte? -> 'CHAR_BIT == 8'
std::cout << '\n' << "'one': " << one << '\n'; // '0000 0000 0000 0001'
// Bit positions that have been vacated by a shift operation are zero-filled:
std::bitset<sizeof (short) * CHAR_BIT > two(1 << 1 /* 1-bit left shift */);
std::cout << "'two': " << two << '\n'; // '0000 0000 0000 0010'
std::bitset<sizeof (short) * CHAR_BIT > zero(1 >> 1 /* 1-bit right shift */);
std::cout << "'zero': " << zero << '\n'; // '0000 0000 0000 0000'

std::bitset<sizeof (short) * CHAR_BIT > minus_one(-1);
std::cout << "'minus_one': " << minus_one << '\n'; // '1111 1111 1111 1111'

// How negative numbers are represented (www.devx.com/tips/Tip/16134):
std::bitset<sizeof (short) * CHAR_BIT > minus_minus_one(~minus_one); // ~'1111 1111 1111 1111' -> '0000 0000 0000 0000'
minus_minus_one[0] = true; // '0000 0000 0000 0001'
std::cout << "'minus_minus_one': " << minus_minus_one << '\n'; // '0000 0000 0000 0001'

// If you left-shift a signed number so that the sign bit is affected, the result is undefined:
std::bitset<sizeof (short) * CHAR_BIT > unknown(16384 << 1); // '0100 0000 0000 0000' << 1
std::cout << "'unknown': " << unknown << '\n'; // '1000 0000 0000 0000'
std::bitset<sizeof (short) * CHAR_BIT > short_min(SHRT_MIN); // '-32768'
std::cout << "'short_min': " << short_min << '\n'; // '1000 0000 0000 0000'

std::cout << '\n' << "'SHRT_MAX': " << SHRT_MAX << '\n' // '0111 1111 1111 1111' / 32767
    << "'SHRT_MIN': " << SHRT_MIN << '\n'; // '1000 0000 0000 0000' / -32768
assert(SHRT_MAX != -SHRT_MIN);
assert(SHRT_MAX == ~SHRT_MIN);
Example (floating point numbers) Numbers.Cpp.zip 
#include <climits> // 'CHAR_BIT'...
#include <cmath> // 'pow'...
…
/**
* Floating point numbers (www.learncpp.com/cpp-tutorial/25-floating-point-numbers/)
* IEEE 754 standard (www3.ntu.edu.sg/home/ehchua/programming/java/datarepresentation.html)
*/
union {
   float f = 1.1F; // '0 - 0111 1111 - 000 1100 1100 1100 1100 1101'
   // -> 1 sign bit + 8 exponent bits + 23 fraction (significant) bits = 32 bits
   uint32_t i; // if 'sizeof (float) == 8' then 'uint64_t'
} _one_point_one;
// S == '0' -> positive
// E == '0111 1111' -> 127
// Fraction ==  '000 1100 1100 1100 1100 1101' -> in IEEE 754 standard, the actual fraction is normalized with an implicit leading '1', so
// the actual fraction is 1.000 1100 1100 1100 1100 1101 = 1 + 2^-4 + 2^-5 + 2^-8 + 2^-9 + 2^-12 + 2^-13 +
// 2^-16 + 2^-17 + 2^-20 + 2^-21 + 2^-23 = 1 + 1/16 + 1/32 + ... = 1.1

// About E: in IEEE 754 standard, the actual exponent is 'E - 127' (so-called excess-127 or bias-127).
// This is because we need to represent both positive and negative exponent.
// With an 8-bit E, ranging from 0 to 255, the excess-127 scheme could provide actual exponent of -127 to 128.

/**
* Final result:
* 1.1 * 2^(E - 127) = 1.1 * 2^0 = 1.1
*/

float check = 1 + pow(2.F, -4.F) + pow(2.F, -5.F) 
  + pow(2.F, -8.F) + pow(2.F, -9.F)
  + pow(2.F, -12.F) + pow(2.F, -13.F)
  + pow(2.F, -16.F) + pow(2.F, -17.F)
  + pow(2.F, -20.F) + pow(2.F, -21.F)
  + pow(2.F, -23.F);

std::bitset<sizeof (uint32_t) * CHAR_BIT > one_point_one(_one_point_one.i);
std::cout << '\n' << "'one_point_one': " << one_point_one << '\n' // '0000 0000 0000 0001'
   << "'check': " << check << '\n';

Numerical stability

Rule(s)
Example Numbers.Cpp.zip 
#include <cfloat> // 'DBL_MAX'...
#include <cmath> // 'isinf', 'INFINITY'...
…
std::cout << '\n' << std::boolalpha << "std::isinf(1 / 0): " << std::isinf(1 / 0) << '\n'; // 'false' because division by zero is undefined here...

std::cout << '\n' << std::boolalpha
    << "std::isnan(NAN): " << std::isnan(NAN) << '\n' // 'true'
    << "std::isnan(INFINITY): " << std::isnan(INFINITY) << '\n' // 'false'
    << "std::isnan(1 / 0.F): " << std::isnan(1 / 0.F) << '\n' // 'false'
    << "std::isinf(1 / 0.F): " << std::isinf(1 / 0.F) << '\n' // 'true'
    << "std::isnan(DBL_MAX * 2.): " << std::isnan(DBL_MAX * 2.) << '\n' // 'false'
    << "std::isinf(DBL_MAX * 2.): " << std::isinf(DBL_MAX * 2.) << '\n' // 'true'
    << "std::isnan(0 / 0.): " << std::isnan(0 / 0.) << '\n' // 'true'
    << "std::isnan(INFINITY - INFINITY): " << std::isnan(INFINITY - INFINITY) << '\n'; // 'true'
See also
C++11 comes with a lot of non-primitive types. A key enhancement is the <chrono> header file that contains time-related types beyond the old-fashion types in the historical <ctime> header file.

Predefined types: the case of <chrono>

Rule(s)
Example
std::chrono::seconds my_duration(5);
using namespace std::chrono_literals; // '<chrono>' reserved suffixes...
std::chrono::milliseconds my_duration_ = 5000ms;
std::this_thread::sleep_for(5s); // Wait for 5s...

Predefined types: the case of std::filesystem::path (C++17)

Rule(s)
Example
std::filesystem::path path("/"); // Unix style adapts to Windows, i.e., "C:\\"
path /= "Users";
path /= "franc";
path /= "Desktop";
path /= "Franck.jpg";
std::cout << "exists(): " << std::boolalpha << std::filesystem::exists(path) << "\n" // 'true'
    << "root_name(): " << path.root_name() << "\n" // ""
    << "root_path(): " << path.root_path() << "\n" // "/"
    << "relative_path(): " << path.relative_path() << "\n" // "Users\\franc\\Desktop\\Franck.jpg"
    << "parent_path(): " << path.parent_path() << "\n" // "/Users\\franc\\Desktop"
    << "filename(): " << path.filename() << "\n" // "Franck.jpg"
    << "stem(): " << path.stem() << "\n" // "Franck"
    << "extension(): " << path.extension() << "\n"; // ".jpg"

if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) {
    std::error_code error_code;
    std::uintmax_t size = std::filesystem::file_size(path, error_code);
    if (size != static_cast<std::uintmax_t>(-1))
        std::cout << "size: " << size << "\n"; // '6176'
    else
        std::cout << "size (error): " << error_code.category().message(error_code.value()) << "\n";
}
See also

Data structures

Rule(s)
Example (.h header file) Numbers.Cpp.zip 
struct My_data_structure { // All properties are by definition 'public:'
    bool bool_attribute;
    char char_attribute;
    unsigned char unsigned_char_attribute;

    short int short_attribute; // <=> 'short' or 'signed short int'
    unsigned short int unsigned_short_attribute; // <=> 'unsigned short'
    int int_attribute; // <=> 'signed int'
    unsigned int unsigned_int_attribute;
    long int long_attribute; // <=> 'long' or 'signed long int'
    unsigned long int unsigned_long_attribute; // <=> 'unsigned long'
    long long int long_long_attribute; // <=> 'long long' or 'signed long long int'
    unsigned long long int unsigned_long_long_attribute; // <=> 'unsigned long long'

    float float_attribute;
    double double_attribute;
    long double long_double_attribute;

    struct { // All properties are by definition 'public:'
        double first;
        double second;
    } struct_attribute;

    union { // All properties are by definition 'public:'
        char is_char;
        int is_int;
    } union_attribute;
};
Example (.cpp header file) Numbers.Cpp.zip 
My_data_structure object;

std::cout << "bool: " << sizeof (bool) << '\n';
std::cout << "char: " << sizeof (object.char_attribute) << '\n';
std::cout << "short: " << sizeof (short) << '\n';
std::cout << "int: " << sizeof (int) << '\n';
std::cout << "long: " << sizeof (long) << '\n';
std::cout << "long long: " << sizeof (long long) << '\n';

std::cout << "float: " << sizeof (float) << '\n';
std::cout << "double: " << sizeof (double) << '\n';
std::cout << "long double: " << sizeof (long double) << '\n';
std::cout << "My_data_structure: " << sizeof (My_data_structure) << "\n\n";

object.bool_attribute = true;
std::cout << object.bool_attribute << '\n';
object.char_attribute = '\r';
std::cout << object.char_attribute << '\n';
object.unsigned_char_attribute = 'a';
std::cout << object.unsigned_char_attribute << '\n';

object.int_attribute = (short) 0xFFFF;
std::cout << object.int_attribute << '\n';
object.unsigned_short_attribute = 0xFFFF;
std::cout << object.unsigned_short_attribute << '\n';
object.int_attribute = (int) 6.5E1;
std::cout << object.int_attribute << '\n';
object.unsigned_int_attribute = (unsigned int) 7.2e-2;
std::cout << object.unsigned_int_attribute << '\n';
object.long_attribute = 500000L;
std::cout << object.long_attribute << '\n';
object.unsigned_long_attribute = 0xFFFFFFFE + 1L;
std::cout << object.unsigned_long_attribute << '\n';
object.long_long_attribute = 9LL;
std::cout << object.long_long_attribute << '\n';
object.unsigned_long_long_attribute = 0xFFFFFFFFFFFFFFFE + 1LL;
std::cout << object.unsigned_long_long_attribute << '\n';

object.float_attribute = 1.F;
std::cout << object.float_attribute << '\n';
object.double_attribute = 1.;
std::cout << object.double_attribute << '\n';
object.long_double_attribute = 1.L;
std::cout << object.long_double_attribute << '\n';

object.union_attribute.is_char = 'A';
std::cout << "'A' as 'char': " << object.union_attribute.is_char << '\n';
std::cout << "'A' as 'int': " << object.union_attribute.is_int << '\n';
object.union_attribute.is_int = 66;
std::cout << "'66' as 'char': " << object.union_attribute.is_char << '\n';
std::cout << "'66' as 'int': " << object.union_attribute.is_int << '\n';

Aggregate initialization

Rule(s)
  • From C++11, brackets may instrument object initialization in a straightforward way. Bracket-based initialization relies on constructors in an implicit way or on std::initializer_list in an explicit way.
Example (implicit) Numbers.Cpp.zip 
std::bitset<CHAR_BIT> a{97}; // 'a'
std::byte a_{97}; // 'a'

// C++17:
std::cout << std::boolalpha << "'std::is_aggregate_v<My_data_structure>': "
    << std::is_aggregate_v<My_data_structure> << std::endl; // 'true'
// C++11 (included: bool, ..., long long) (excluded: enum, float...) :
std::cout << std::boolalpha << "'std::is_integral<decltype(object.char_attribute)>': "
    << std::is_integral_v<decltype(object.char_attribute)> << std::endl; // 'true'

// C++14:
My_data_structure another_object{false, 'a', 'a', 1, 1, 1, 1, 1L, 1L, 1LL, 1LL, 1.F, 1., 1.L, {1., 1.}};
// C++20 (designated initialization):
My_data_structure yet_another_object{.bool_attribute = false /*,.char_attribute = 'a'*/, .unsigned_char_attribute = 'b'};

std::string FB[] = {"Franck", /* list initialization -> */ {'B', 'a', 'r', 'b', 'i', 'e', 'r'}};
wchar_t F[] = L"Franck";
Example (explicit) Lambda_expression_.Cpp.zip 
'.h' file:
class Election {
    std::string _separator;
    std::unordered_multimap<std::string, std::string> _situation;
public:
    Election(const std::string&, const std::initializer_list<std::unordered_multimap<std::string, std::string>::value_type>&);
    …
};

'.cpp' file:
Election::Election(const std::string& separator, const std::initializer_list<std::unordered_multimap<std::string, std::string>::value_type>& situation) {
    _separator = separator;
    for (std::unordered_multimap<std::string, std::string>::value_type pair : situation) // "Range-based for"
        _situation.insert(pair);
}
…
Election French_2012_presidential_election{ " - ",
        {
            {"Macron", Election::President},
            {"Macron", Election::Candidate},
            {"Philippe", Election::Prime_minister},
            {"Mélanchon", Election::Challenger},
            {"Mélanchon", Election::Candidate},
            {"Le Pen", Election::Challenger},
            {"Le Pen", Election::Candidate}
        }};

User-defined suffixes

Rule(s)
  • From C++11, literals (integers, characters, floating-point numbers, strings, booleans and pointers) may be suffixed to reinforce the type of a literal towards an existing (see <chrono> above) or user-defined type.
Example (existing versus user-defined literal suffix) Inline_namespace.Cpp.zip 
'.h' file:
namespace New_York_City_Penitentiary {
    class Prisoner {
        const std::string _prison_file_number;
        …
    public:
        explicit Prisoner(std::string&&);
        …
    };
    …
    // Literal suffix (re)-definition cannot be a member function: 
    Prisoner operator ""_Prisoner(const char[], size_t); // '_' is required not to conflict with hypothetical (future) use of 'Prisoner' as suffix...
}

'.cpp' file:
New_York_City_Penitentiary::Prisoner::Prisoner(std::string&& prison_file_number) : _prison_file_number(prison_file_number) {
}
New_York_City_Penitentiary::Prisoner New_York_City_Penitentiary::operator ""_Prisoner(const char prison_file_number[], size_t size) {
    std::string _prison_file_number(prison_file_number);
    return New_York_City_Penitentiary::Prisoner(std::move(_prison_file_number));
}
…
using namespace New_York_City_Penitentiary;
using namespace std::literals::string_literals; //// Operator""s is made visible...

// Prisoner fb = "1630125388055-29"s; // Compilation error: 'explicit' constructor precludes implicit conversion...
Prisoner fb = "1630125388055-29"_Prisoner;
See also
Historically, C++ arrays are managed as pointers. However, C++ tends to increase type checking at compilation time that prevents potential errors at run-time.
Example
char* given_name = {'F','r','a','n','c','k'}; // Old style, compilation error in "modern" C++!         
char given_name[] = {'f','r','a','n','c','k'}; // Better!
given_name[0] = 'F';
Rule(s)
Example
T tab[1000]; // Fixed capacity
// Alternatively:
T tab[]; // Variable capacity
tab = new T[1000] // Allocation of memory
delete[] tab; // Full desallocation of memory while 'delete[500] tab;' is a partial desallocation because '500' < '1000'
See also
In C++, enumerated types raise the problem of matching to int. Recent improvements occur through scoped enumerated types.
Example (non-scoped)
class Temperature {
public:
    enum Temperature_unit {Celsius, Fahrenheit, Kelvin};
    …
};
Example (scoped)
enum class Medal {Gold, Silver, Bronze};
// Incorrect: 'Medal award = Gold;'
Medal award = Medal::Gold;
// Incorrect (matching to 'int'): 'int i = Medal::Gold;'
Example (choose char as backbone type: integral types only!)
enum class Direction : char {East = 'E', South = 'S', West = 'W', North = 'N'};
assert(sizeof(Direction) == 1);
// Using related 'std::underlying_type' trait:
static_assert(std::is_same<std::underlying_type<Direction>::type, char>::value, "'Direction' has not 'char' as underlying type, why?");
See also
C++ offers reusable predefined data structures. User-defined data structures thus just aim at completing missing parts in applications.
Example
std::time_t now = std::time(&now); // '#include <ctime>'
std::tm *now_as_data_structure = std::gmtime(&now);
int year = now_as_data_structure->tm_year + 1900; // Caution: 'tm_year' returns the current year minus '1900'!
Rule(s)
Example
class Program {
    Temperature _target_temperature;
    std::tm _time; // 'std::tm' is an old C data structure that requires '#include <ctime>'
}

class Programmable_thermostat {
private:
    Program _program[8]; // An attribute named '_program' as an array of 8 values, each having 'Program' as type
    …
Resource(s)
See also
In OO programming, attributes aim at being hidden (Parnas' information hiding principle) to avoid any direct (unsafe) access from any code outside data structures.
Instead, functions are generally exposed. Only internal (reusable) computations are hidden, leading to inherent (private) functions.
Rule(s)
Example (Smalltalk)
get_x
    "return of _x"
    ^_x.
set_x: x
    "assign _x with x"
    _x := x.
Rule(s)
Example
// '.h' file
class My_class {
    public:
        My_class(float = 0.F); // This is imposed by the necessity of defining the value of the 'b' constant!
        float a; // To be avoided, absolutely!
        const float b; 
    private:
        double _c;
    …
};

// '.cpp' file(s):
My_class::My_class(float my_f) : b(my_f) /* 'b' constant setup */ { …

My_class mc;
mc.a = 1.F; // OK because 'public:'
mc.b = 2.F; // Compilation error because 'const'
std::cout << mc.b << std::endl; // OK because 'public:'
mc._c = 3.; // Compilation error because 'private:'
std::cout << mc._c << std::endl; // Compilation error because 'private:'
Rule(s)
Example
// '.h' file
class My_class {
    …
    private:
        void _f();
    public:
        void g(); // '_f' is probably called inside 'g' and/or in another method…
};

// '.cpp' file:
My_class mc;
mc._f(); // Compilation error because 'private:'
mc.g(); // OK because 'public:'

Class attributes and functions

Rule(s)
Example
// '.h' file:
class Temperature {
public:
    static const float Min;
    …
};

// '.cpp' file:
const float Temperature::Min = -273.15F; // In Celsius

if(_value < Min) … // Or 'Temperature::Min' when one accesses this (public) attribute from outside the 'Temperature' class
Rule(s)
Example
// '.h' file:
class Leap_year_utility {
private:
    std::tm _time; // '#include <ctime>'
public:
    static int January();
    int february() const;
    …
    bool leap_year() const; // Result depends on '_time'
};

// '.cpp' file:
int Leap_year_utility::January() {
    return 31;
}
int Leap_year_utility::february() const {
    return leap_year() ? 29 : 28;
}
…
See also
Visibility and encapsulation are such that the hidden part is called “the implementation” while the visible part is called “the interface”. Visibility possibilities are based on the private, protected (in relation with inheritance) and public keywords.
Example (non-encapsulation)
#include <cstdio>
#include <ctime>

int main(int argc, char** argv) {

    std::time_t t = 0L; // One refers to the 'long' primtive type, which means "non-encapsulation" -> very bad idea!
    std::printf(std::asctime(std::gmtime(&t))); // January 1, 1970, 00:00:00 GMT
    t = -1L; // That's the reason why encapsulation is important. Doing this is permissive -> again, very bad idea!
    std::printf(std::asctime(std::gmtime(&t))); // This may work, but…

    return 0;
}

Variations on visibility

Rule(s)
Example
// '.h' file:
class Real {
    private: // "implementation" part
        std::vector<char> _implementation; // Machine-based representation through a predefined type, i.e., 'std::vector' ('char' plays the role of byte)
    public: // "interface" part
        Real(std::string); // To create huge 'Real' objects beyond 'double' capacity
    …
};

// '.cpp' file:
Real r("99999999999999999999999999999999999999999999999999999");
Rule(s)
Example
// '.h' file:
class Prisoner {
    private:
        const std::string _file_number;
    public:
        Prisoner(const std::string&);
        bool equals(const Prisoner&) const;
};

// '.cpp' file:
Prisoner::Prisoner(const std::string& file_number) : _file_number(file_number) {
}

bool Prisoner::equals(const Prisoner& p) const {
// 'std::string' comparison: http://en.cppreference.com/w/cpp/string/basic_string/compare
    if (this->_file_number.compare(p._file_number) != 0) return false; // No compilation error while '_file_number' is a priori inaccessible!
    return true;
}

Friend functions

Rule(s)
Example
// '.h' file:
#ifndef _Friend_h
#define _Friend_h

#include <string>

class B; // Forward reference

class A {
public:
    void f(const B&) const;
};

class B {
    int _i;
    friend void A::f(const B&) const;
};

class Reader; // Forward reference

class Phrase; // Forward reference

class Expression {
    std::string _content;
public:
    Expression(const std::string&);
private:
    std::string _read() const;
    friend Phrase operator+(const Phrase&, const Expression&); // Here, the '+' operator is not a member function
    friend class Reader;
};

class Phrase {
    const std::string _content;
public:
    Phrase(const std::string&);
    friend Phrase operator+(const Phrase&, const Expression&); // Here, the '+' operator is not a member function
    friend class Reader;
};

class Reader {
public:
    std::string read(const Expression&) const;
    std::string read(const Phrase&) const;
};

#endif
// '.cpp' file: 
#include <iostream>

#include "Friend.h"

void A::f(const B& b) const {
    b._i;
}

Expression::Expression(const std::string& s) : _content(s) {
}

std::string Expression::_read() const {
    return _content;
}

Phrase::Phrase(const std::string& s) : _content(s) {
}

Phrase operator+(const Phrase& p, const Expression& e) {
    Phrase result(p._content + e._read()); // Access to properties of 'Expression' and 'Phrase'
    return result;
}

std::string Reader::read(const Expression& e) const { // Access to private properties of 'Expression'
    return e._content;
}

std::string Reader::read(const Phrase& p) const { // Access to private properties of 'Phrase'
    return p._content;
}

int main(int argc, char** argv) {
    Reader FranckBarbier;
    Expression e("Caution! Avoid it... What?");
    Phrase p("The 'friend' keyword... ");
    std::cout << FranckBarbier.read(e) << '\n';
    std::cout << FranckBarbier.read(p) << '\n';
    std::cout << FranckBarbier.read(operator+(p, e)) << '\n';

    return 0;
}
Resource(s)
See also
Modifiers are additional information associated with attributes and functions. Their composition is sometimes impossible and/or useless.

Attribute modifiers

Function modifiers

See also
Compared to Java, naming space in C++ does not rely on hierarchical directories of the Operating System (OS).
Example
#include <string>
…
std::string s; // The 'string' type is accessed in an absolute way through its namespace, i.e., 'std'

// Alternatively:
#include <string>
…
using namespace std;
…
string s; // The 'string' type is accessed in a relative way through its namespace
Rule(s)
Example
namespace Franck {
	class C { …
    …
}

namespace Barbier = Franck;

using namespace Barbier; // Or 'using namespace Franck;'
…
C c; // Instead of 'Barbier::C c;'

Inline namespace

Rule(s)
Example Inline_namespace.Cpp.zip 
namespace New_York_City_Penitentiary {
    inline namespace DAOs {
        class Criminal_case { … };
    …
}
// Later on...
… New_York_City_Penitentiary::Criminal_case … // 'DAOs' is not used!
Example Inline_namespace.Cpp.zip 
namespace New_York_City_Penitentiary {
    …
    namespace Nominal {
        class Prisoner {
        public:
            explicit Prisoner(const std::string&);
            …
        …
    }
    inline namespace Ver_2 {
        class Prisoner {
        public:
            Prisoner(std::string&&);
            …
        …
    }
}
// Later on...
New_York_City_Penitentiary::Nominal::Prisoner::Prisoner(const std::string& prison_file_number) : _prison_file_number(prison_file_number) {}
…
New_York_City_Penitentiary::Prisoner::Prisoner(std::string&& prison_file_number) : _prison_file_number(prison_file_number) {}
…
using namespace New_York_City_Penitentiary;
using namespace std::literals::string_literals; // Operator""s is made visible...

Criminal_case criminal_case; // 'DAOs::Criminal_case' is not required...

Nominal::Prisoner p("1630125388055-29"s); // Explicit "nominal" version...
p.set_date_of_incarceration(std::tm{.tm_mday = 13, .tm_mon = 10, .tm_year = 119}); // 13/11/2019
p.set_incarceration_main(&criminal_case);

Prisoner p_("1630125388055-29"s); // Last version, i.e., 'Ver_2'...
p.set_date_of_incarceration(std::tm{.tm_mday = 13, .tm_mon = 10, .tm_year = 119}); // 13/11/2019
p_.set_incarceration_main(&criminal_case); // Do much: '_offense.insert(criminal_case);'
See also

Source file organization

Rule(s)
Example
// 'Elephant.h' file (declarations):
#ifndef _Elephant // Framing in case of multiple inclusions of this file
#define _Elephant
#include <cstddef> // Predefined entities as 'NULL' or 'nullptr', etc.
… // Other possible inclusions here…
class Elephant {
    static void* _Preallocated_memory;
    …
};
#endif // End of framing

// 'Elephant.cpp' file:
#include <cstddef> // One MUST NOT take into account that 'Elephant.h' already includes '<cstddef>'
… // Other possible standard inclusions here…
#include "Elephant.h" // Access to 'Elephant' class
… // Other possible local inclusions here…
void* Elephant::_Preallocated_memory = nullptr;
See also
In C++, multiple constructors may exist while it exists only one destructor without parameters. The latter can declared as virtual. By default, for any class, C++ automatically generates one destructor and one constructor without parameters. Introducing a constructor (with or without parameters), respectively a destructor, erases that generated by C++.
Example
#ifndef _Horner_h
#define _Horner_h

class Horner { // Polynomial evaluation according to different methods
    int _size;
    double* _representation;
public:
    Horner(int);
    ~Horner();
    …
};

#endif
Horner::Horner(int size) : _size(size) {
    assert(_size > 0);
    _representation = new double[_size]; // 'new' operator
    std::time_t t;
    std::srand(std::time(&t));
    for (int i = 0; i < _size; i++) _representation[i] = (double) std::rand();
}

Horner::~Horner() {
    delete[] _representation; // 'delete' operator to cancel effect of 'new' in 'Horner' constructor
}

Reminder on memory management: what to do and… not to do!

Example
// '.h' file:
class Word {
private:
    char* _implementation;
public:
    Word();
    Word(char*);
    ~Word();
    std::string toString() const; // '#include <string>'
};

// '.cpp' file:
std::string Word::toString() const {
    std::string result(_implementation); // '#include <string>'
    return result;
}

Word::Word() {
    _implementation = new char[1];
    _implementation[0] = 0; // This is the way to create an empty string in C!
}

Word::Word(char* s) {
    _implementation = new char[std::strlen(s) + 1]; // '#include <cstring>'
    std::strcpy(_implementation, s); // '#include <cstring>'
}

Word::~Word() {
    if (_implementation) delete[] _implementation;
}

int main(int argc, char** argv) {
    std::string Franck = "Franck"; // '#include <string>'
    Word* w1 = new Word((char*) Franck.c_str());
    std::cout << w1->toString() << std::endl; // '#include <iostream>'
    delete w1; // OK

    Word w2((char*) Franck.c_str());
    std::cout << w2.toString() << std::endl;
    delete &w2; // Damnation! 

    return 0;
}

Overloading and delegation

Example
// '.h' file:
class Limited_bit_stream {
…
// Constructors' overloading (as in Java, overloading applies to other functions as well):
public:
    Limited_bit_stream();
    Limited_bit_stream(const char[]);
    Limited_bit_stream(Bit_stream_format);
    …
};

// '.cpp' file:
Limited_bit_stream::Limited_bit_stream(const char a_string[]) : Limited_bit_stream() { … // From C++11, constructors may call others: this is named "constructor delegation"
Resource(s)
See also
Basic C++ operators as +, -, *, /, (),[]… may be contextually redefined for a given type.

Redefining common operators: *, <, etc.

Example
// '.h' file:
class Polynomial {
    …
public:
    …
    Polynomial operator *(const Polynomial&) const;
    …
};

// '.cpp' file:
Polynomial a, b;
// 'a' and 'b' are filled…
Polynomial c = a * b; // Alternative notation: 'c = a.operator *(b);'
Example
// '.h' file:
class Elephant : public Elephantidae {
    …
    short _weight;
public:
    …
    bool operator<(const Elephant&) const; 
};

// '.cpp' file:
bool Elephant::operator<(const Elephant& e) const {
    return this->_weight < e._weight;
}
In C++, initialization and assignment are radically different. Initialization relies on the copy constructor while assignment is the possible redefinition of the = operator.
Rule(s)
Example Student.Cpp.zip 
// '.h' file:
class Student {
private:
    const Student* * _my_friends; // 'const Student* _my_friends[];' does not allow later assignment through 'new' in particular
public:
    Student(int = 5);
    Student(const Student&); // Copy constructor
    ~Student(); // Required destructor
// '= delete' or '= default' not applicable due to returned object is 'const':
    const Student& operator=(const Student&); // Assignment redefinition
};

// '.cpp' file:
Student::Student(int my_friends_capacity) {
    _my_friends = new const Student*[my_friends_capacity];
}
Student::Student(const Student& s) {
    _my_friends = new const Student*[sizeof (s._my_friends) / sizeof (s._my_friends[0])];
    for (int i = 0; i<sizeof (s._my_friends) / sizeof (s._my_friends[0]); i++) {
        _my_friends[i] = s._my_friends[i];
    }
}
Student::~Student() {
    delete[] _my_friends;
}
const Student& Student::operator=(const Student& s) {
    if (this != &s) { // Weird case: 'Student s; s = s;'
        this->~Student(); // Caution, unreliable code!
        this->_my_friends = new const Student*[sizeof (s._my_friends) / sizeof (s._my_friends[0])];
        for (int i = 0; i<sizeof (s._my_friends) / sizeof (s._my_friends[0]); i++) {
            this->_my_friends[i] = s._my_friends[i];
        }
    }
    return *this;
}
…
int main(int argc, char** argv) {
    Student Franck(10);
    Student FranckBis = Franck; // Initialization!
    Student FranckTer;
    FranckTer = Franck; // Assignment!

    return 0;
}
C++11 introduces (in an official way) the idea of “rvalue” opposite to that of “lvalue”. More formally, the current context in C++14, C++17 and, C++20 is the distinction between pure “rvalue” (a.k.a. “prvalue”), “lvalue”, “xvalue”… Further detail here

“Move” semantics

Rule(s)
Example (foundation) Rvalue.Cpp.zip 
// '.h' file:
class Person : … {
    private:
        static const std::string _Default_identity;
    public:
        static Person Default_person();
    …

// '.cpp' file:
const std::string Person::_Default_identity = "Anybody";
Person Person::Default_person() {
    return Person(_Default_identity);
}
…
// Compilation error:
// Person& who = Person("who"); // A "lvalue" cannot bind a "temporary" object, i.e., a "rvalue"...
// Copy elision through optimization, i.e., the move constructor *IS NOT* called:
Person&& who = Person("who"); // While a "rvalue" can!

// The 'Person' object returned in 'Person::Default_person' is *MOVED* from callee context to caller context
// *WITHOUT* superfluous copy...
// This often was a compilation optimization that became a developer-controlled mechanism from C++11:
Person&& default_person = Person::Default_person(); // Debugger shows that copy *ISN'T* called...
Example (bypass copy, force move) Rvalue.Cpp.zip 
// '.h' file:
class Person : … {
    …
    public:
        const std::string identity;
    private:
        Resource* _resource = nullptr;
    public:
        Person(const std::string& = "");
        Person(const Person&);
        virtual ~Person();
        Person& operator=(Person const& /* <=> 'const Person&' */); // Copy assignment
        Person& operator=(Person&&) noexcept; // Move assignment
        void becomes(Person&&);
        Resource* const get_resource() const;
};

// '.cpp' file:
Person& Person::operator=(Person&& p) noexcept { // Move assignment
    const_cast<std::string&> (this->identity) = p.identity;
    // Move semantics:
    std::swap(_resource, p._resource); // 'delete _resource;' on 'p' is later done when "rvalue" is destroyed...
    return *this;
}
…
Person someone;
// 'static Person GetInstance(const std::String& s) { Person p(s); return p; } // Deletion of 'p'...
// "Move constructor" ('return p;') and next "move assignment":
someone = Person::GetInstance("someone else...");
Rule(s)
Example Rvalue.Cpp.zip 
Person EmmanuelMacron("EmmanuelMacron");
Person presidentOfFrenchRepublique;
presidentOfFrenchRepublique = std::move(EmmanuelMacron); // Move assignment ('_resource' fields are exchanged...)
assert(EmmanuelMacron.get_resource() != nullptr);
Rule(s)
Example Rvalue.Cpp.zip 
void Person::becomes(Person&& p) { // 'p' is "lvalue" since it has a name!
    *this = p; // 'Person& Person::operator=(Person const& p)' is called...
}
…
Person anybody;
// 'static Person GetInstance(const std::String& s) { Person p(s); return p; } // Deletion of 'p'...
anybody.becomes(Person::GetInstance("anyone"));

Perfect forwarding

Rule(s)
Example (forwarding, reminder)
class A;
class B { A& _a; };
class A { B& _b; };
Rule(s)
Example (adapt between “lvalue” and “rvalue”: failure) Rvalue.Cpp.zip 
Person Person::GetClone(Person& p) {
    /* Change 'p' in some way...*/ Person _p = p; return _p;
} // Deletion of '_p'...
Person Person::GetClone(const Person& p) {
    /* Change 'p' in some way...*/ Person _p = p; return _p;
} // Deletion of '_p'...
Person Person::GetClone(Person&& p) { 
    /* Change 'p' in some way... */
    // 'std::forward' brings no value here since *THERE IS NO DEDUCTION FROM TEMPLATE INSTANTIATION*:
    Person _p(std::forward<Person>(p)); // Forwards "lvalue" either as "lvalue" or as "rvalue", depending on 'p'...
    return _p;
} // Deletion of '_p'...
…
// Person attendee = Person::GetClone(Person::GetInstance("attendee")); // Compilation error: "lvalue" required...
Person attendee = Person::GetClone(Person::GetInstance("attendee")); // This works with 'const Person& p' since "rvalue" "disappears"...
Person attendee_ = Person::GetClone(Person::GetInstance("attendee_")); // "rvalue" passed, OK...
Rule(s)
Example (adapt between “lvalue” and “rvalue”: success) Rvalue.Cpp.zip 
template<typename O> O GetClone(O&& o) { // Global namespace...
    // Change 'o' in some way...
    O _o(std::forward<O>(o)); // Forwards "lvalue" either as "lvalue" or as "rvalue", depending on 'o'...
    return _o;
} // Deletion of '_o'...
…
Person FranckBarbier("FranckBarbier");
Person& Bab = FranckBarbier; // Copy constructor ("lvalue"): '_resource' is shared...
assert(FranckBarbier.get_resource() != nullptr && Bab.get_resource() != nullptr && FranckBarbier.get_resource() == Bab.get_resource());

Person trainer = ::GetClone_/*<Person&>*/(FranckBarbier); // "lvalue"
assert(FranckBarbier.get_resource() != nullptr && trainer.get_resource() != nullptr && FranckBarbier.get_resource() != trainer.get_resource());
See also
The default and delete keywords may, from C++11, be associated with “implicit” functions: constructors (base, copy, move), destructor and assignment (copy, move).
Rule(s)
Example Default_delete.Cpp.zip 
'.h' file:
class My_class { // 'inline' is for compactness only!
private:
    // 'std::is_trivially_copyable<My_class>: false':
    // 'std::is_trivially_assignable<My_class, My_class>': false:
    // 'std::is_trivially_move_constructible<My_class>': false:
    std::string _resource;
    // To prevent verbose writing of 'My_class::My_class() {}' in '.cpp' file:
    My_class() = default; // 'std::is_trivially_constructible<My_class>': false
public:

    // 'std::is_constructible<My_class, std::string>': true':
    inline My_class(std::string s) : _resource(s) {};

    // 'std::is_copy_constructible<My_class>': false:
    // 'std::is_assignable<My_class, My_class>': false:
    // 'std::is_move_constructible<My_class, My_class>': true:
    inline My_class(My_class&& mc) : _resource(std::move(mc._resource)) {}

    My_class(const My_class&) = delete; // 'std::is_copy_constructible<My_class>': false && 'std::is_move_constructible<My_class, My_class>': false
    My_class& operator=(const My_class&) = delete; // 'std::is_assignable<My_class, My_class>': false

    // 'std::is_assignable<My_class, My_class>': true:
    inline My_class& operator=(My_class&& mc) { // Move assignment
        _resource = std::move(mc._resource);
        return *this;
    };

    //    To prevent verbose writing of 'My_class::~My_class() {}' in '.cpp' file:
    virtual ~My_class() = default; // Polymorphic type => !triviality
};

// '.cpp' file:
My_class mc("mc");

std::cout << std::boolalpha << "'std::is_trivially_constructible<My_class>': " <<
            std::is_trivially_constructible<My_class>::value << std::endl; // 'false'
std::cout << std::boolalpha << "'std::is_constructible<My_class, int>': " <<
            std::is_constructible<My_class, std::string>::value << std::endl << std::endl; // 'true'

std::cout << std::boolalpha << "'std::is_trivially_copyable<My_class>': " <<
            std::is_trivially_copyable<My_class>::value << std::endl; // 'false'
//    My_class mc_ = mc; // Compilation error because copy constructor has been deleted
std::cout << std::boolalpha << "'std::is_copy_constructible<My_class>': " <<
            std::is_copy_constructible<My_class>::value << std::endl << std::endl; // 'false'

My_class mc_("mc_");
//    mc = mc_; // Compilation error because copy assignment has been deleted
mc = std::move(mc_); // Move assignment
mc = My_class("Move assignment"); // Move assignment

std::cout << std::boolalpha << "'std::is_trivially_assignable<My_class, My_class>': " <<
            std::is_trivially_assignable<My_class, My_class>::value << std::endl; // 'false'
std::cout << std::boolalpha << "'std::is_assignable<My_class, My_class>': " <<
            std::is_assignable<My_class, My_class>::value << std::endl << std::endl; // 'true'

My_class mc__(My_class("Move constructor"));
std::cout << std::boolalpha << "'std::is_trivially_move_constructible<My_class>': " <<
            std::is_trivially_move_constructible<My_class>::value << std::endl; // 'false'
std::cout << std::boolalpha << "'std::is_move_constructible<My_class>': " <<
            std::is_move_constructible<My_class>::value << std::endl; // 'true'
Example (stupid people?)
class X {
public:
    ~X() = delete;
};

// Later on, in '.cpp' file:
// X x; // Compilation error: somehow late but safe anyway...
Inheritance is a foundation of OO programming. The principle behind inheritance is the fact that data structures are extended from existing ones. This amounts to adding attributes (structural inheritance) and/or functions (behavioral inheritance). The way of dealing with inheritance in C++ is the use of the : sign. Note that C++ supports multiple inheritance between classes.
Example of inheritance tree (in French)

Structural inheritance

Example
class Compte_bancaire {
        int _id;
    protected:
        float _solde;
    …

class Compte_cheque : public Compte_bancaire {
    protected:
        float _taux_interet;
        float _seuil;
    …

Behavioral inheritance

Example
class Compte_bancaire {
    …
    public:
        inline int id() const {return _id;} // This function is usable by 'Compte_cheque' objects!
    …

Property extension

Example
// '.h' file:
class Compte_epargne_logement : public Compte_epargne { 
    public:
        const static float Taux_interet; // Fixed rate in the French law
    public:
        virtual float taux_interet() const;
    …

// '.cpp' file:
const float Compte_epargne_logement::Taux_interet = Livret_A::Taux_interet * 2.F / 3.F;
float Compte_epargne_logement::taux_interet() const {
    return Taux_interet;
}
…

Inheritance and constructors

Example
// '.h' file:
class Compte_epargne : public Compte_bancaire {
    protected:
        Compte_epargne(int,float = 0.F);
};

// '.cpp' file:
Compte_epargne::Compte_epargne(int id,float solde) : Compte_bancaire(id,solde) {}

Overriding (redefinition)

Example
// '.h' file:
class Compte_bancaire {
    …
    public:
        …
        virtual float taux_interet() const = 0; // Abstract function
        virtual void appliquer_taux_interet();
};

class Compte_cheque : public Compte_bancaire {
    …
    public:
        …
        virtual float taux_interet() const; // Abstract nature is removed when overriding
        virtual void appliquer_taux_interet(); // Overriding as well
};

// '.cpp' file:
void Compte_bancaire::appliquer_taux_interet() {
    _cumul_interets = _solde * (1.F + (taux_interet() / 100.F));
}
float Compte_cheque::taux_interet() const {
    return _taux_interet;
}
void Compte_cheque::appliquer_taux_interet() {
    if(_solde > _seuil) Compte_bancaire::appliquer_taux_interet();
}

Accessing properties of ancestor classes

Example
// Assumption: 'Daughter' inherits from 'Mother', which inherits from 'Grandmother'. One wants in 'Daughter' to access to 'jewel' (not 'private') in 'Mother':
Mother::jewel;
// One now wants in 'Daughter' to access to 'other_jewel' (not 'private') in 'Grandmother':
Grandmother::other_jewel;

final and override keywords

Rule(s)
Example (inheriting with public from the predefinedstd::stack C++ component (#include <stack>))
template <typename T> class Bound_stack : public std::stack<T> {
private:
    const typename std::stack<T>::size_type _capacity;
public:
    Bound_stack(const typename std::stack<T>::size_type&);
    bool full() const;
    void push(const T&);
};

template <typename T> Bound_stack<T>::Bound_stack(const typename std::stack<T>::size_type& capacity) : _capacity(capacity) {
}

template <typename T> bool Bound_stack<T>::full() const {
    return _capacity == this->size();
}

template <typename T> void Bound_stack<T>::push(const T& t) {
    if (full()) throw "push";
    std::stack<T>::push(t);
}
std::stack<char>* bug = new Bound_stack<char>(1); // 'private' inheritance prevents such an assignment
bug->push('a');
bug->push('b'); // Since 'push' is not virtual in 'Bound_stack' then 'push' from 'stack' (the type of 'bug') is called
delete bug; // 'stack' destructor is called while 'bug' effectively points to a 'Bound_stack' object
Rule(s)
Example (not using final)
class Secret {
private:
    virtual void cypher();
public:
    void send_message();
};

class Hack : public Secret {
private:
    void cypher() override; // Check "true" overriding, compiler error otherwise!
};
void Secret::cypher() {
    std::cout << "Secret: let's cypher…" << std::endl;
}
void Secret::send_message() {
    cypher();
}
void Hack::cypher() {
    std::cout << "Hack: let's bypass 'cypher'!" << std::endl;
}
…
Hack* h = new Hack; // Don't forget to use 'delete' later on!
h->send_message(); // 'Hack: let's bypass 'cypher'!' is displayed
Example (using final)
class Secret {
private:
    virtual void cypher() final; // Compilation error in 'Hack' when attempting to override 'cypher'
    …

Final class

Rule(s)
Example
class Temperature final { …

Inheritance and visibility

Rule(s)
Example
std::string C::format() const {
    // A::_a; // Error because 'A::_a' is 'private'
    // B::_a; // Error because 'B::_a' is 'private'
    // A::_b; // Error because 'class B : private A'
    // A::c; // Error because 'class B : private A'
    return B::_b + B::c + _a + _b + c;
}

std::string D::format() const {
    // A::_a; // Error because 'A::_a' is 'private'
    // B::_a; // Error because 'B::_a' is 'private'
    // C::_a; // Error because 'C::_a' is 'private'
    // A::_b; // Error because 'class B : private A'
    // A::c; // Error because 'class B : private A'
    return C::_b + C::c + B::_b + B::c + _a + _b + c;
}

int main() {
    D* d = new D;
    std::cout << d->format() << std::endl;
    C* c = d;
    std::cout << c->format() << std::endl; 
    // B* b = d; // Error because 'class C : protected B'
    // std::cout << d->format() << std::endl;
    // A* a = d; // Error because 'class B : private A'
    // std::cout << a->format() << std::endl;
    delete d;
    return 0;
}
Resource(s)
See also
Polymorphism is intimately associated with inheritance. Polymorphism relies on the testing of objects' type at run-time to choose the “right” code. Contrary to Java, polymorphism is by default disabled in C++. The virtual keyword must then be used to enact polymorphism. Otherwise, C++ imposes the use of pointers or references to play polymorphism, but references are better than pointers.
Example (pointers):
Compte_cheque cc(1963,10500.F,2.F,10000.F);
Compte_bancaire* cb = &cc; // 'cb' points to 'cc' since their mutual types are compatible through inheritance
cb->appliquer_taux_interet(); // 'appliquer_taux_interet' in 'Compte_cheque' is run since the runtime type of 'cb' is 'Compte_cheque'
cb = &cel; // Assumption: 'cel' is a direct instance of 'Compte_epargne_logement'
cb->appliquer_taux_interet(); // Polymorphism again
Example (references):
Compte_bancaire& cb = cc;
cb.appliquer_taux_interet();
cb = cel;
cb.appliquer_taux_interet();
Rule(s)
Example
Animal* a1 = new Cat; // Assumption: 'Cat' directly or indirectly inherits from 'Animal'
Cat c;
Animal& a2 = c;

Polymorphism does not work in a constructor

Example (polymorphism fails) Inheritance_polymorphism.Cpp.zip 
// '.h' file:
class Note {
    …
private:
    virtual void initialization();
    …
public:
    Note(std::istringstream * const);
    …
};

class Confidential_note : public Note {
    …
private:
    void initialization();
public:
    Confidential_note(std::istringstream * const);
    …
};

// '.cpp' file:
void Note::initialization() {
    …
}
// Contrary to Java, event though 'Note::initialization' is declared 'virtual', polymorphism cannot apply because the call occurs inside the constructor!
Note::Note(std::istringstream * const source) : _source(source) {
    initialization(); 
}
void Confidential_note::initialization() {
    … // Polymorphic behavior, which may possibly include 'Note::initialization();'
}
// One expects that, by polymorphism, 'Confidential_note::initialization' is called -> WRONG!
Confidential_note::Confidential_note(std::istringstream * const source) : Note(source) {}
Example (mandatory adaptation) Inheritance_polymorphism.Cpp.zip 
// '.cpp' file:
…
Confidential_note::Confidential_note(std::istringstream * const source) : Note(source) {
    initialization(); // One must explicitely call 'Confidential_note::initialization'
}
See also
A virtual destructor allows the polymorphic call of a destructor. So, the call depends upon the runtime type of the destroyed object.
Example Virtual_destructor.Cpp.zip 
class Expression {
    …
    virtual ~Expression();
    …
class Sentence : public Expression {
    …
    virtual ~Sentence(); // For descendants of 'Sentence'
    …

// Later on, in '.cpp' file:
char separators[] = {' ', '-'};
Expression* e = new Sentence((char*) "Franck Barbier", separators);
…
delete e; // Good, destructor in 'Sentence' is called!
Multiple inheritance is the possibility of having more than one direct mother class. This mechanism must be considered as tricky, even useless, since many OO languages do not support it. However, it may sometimes become useful in certain situations.
Example
// '.h' file:
class Ornithorhynchus : public Mammal, public Oviparous { …
class Echidna : public Mammal, public Oviparous { …
Rule(s)
Example
class iostream : public istream, public ostream { // This is the standard definition in the '<iostream>' file
    …
};
Rule(s)
Example
class Animal {
    protected:
        std::list<Animal*> _kids;
    public:
        inline void Animal::birth(Animal* animal) {_kids.push_back(animal);} // Here, 'inline' is only for the sake of brevity!
    …

class Mammal : virtual public Animal { …
 
class Oviparous : virtual public Animal { …

Multiple inheritance and visibility

Rule(s)
  • Mixing multiple inheritance and visibility may lead to tricky situations.
Example
class A {
    public:
        virtual void f();
};
class B : public A {
    public:
        virtual void f();
};
class C : A {
    public:
        virtual void f();
};
class D : B,C {
    public:
        void g();
};

// Later on, in '.cpp' file:
void D::g() {
    A* pA1;
    // pA1 = this; // Compilation error because two paths exist from 'D' to 'A'
    pA1 = (B*)this; // Path is chosen, OK
    // pA1 = (C*)this; // Compilation error 'C' inherits from 'A' in a private mode
    pA1->f();
}
Resource(s)
See also
C++ supports genericity like Ada, Eiffel, Java
Example Simple_genericity.Cpp.zip 
// '.h' file:
template <typename T> class LIFO {
private:
    std::list<T> _representation; // '#include <list>'
public:
    bool empty() const;
    void in(const T&);
    T out(); // This returns a copy!
};
template <typename T> bool LIFO<T>::empty() const {
    return _representation.empty();
}
template <typename T> T LIFO<T>::out() {
    if (empty()) throw "empty…";
    T t = _representation.back();
    _representation.pop_back();
    return t;
}
template <typename T> void LIFO<T>::in(const T& t) {
    _representation.push_back(t);
}
// '.cpp' file:
class Elephant {
  std::string _name;
public:
  inline Elephant(std::string name) : _name(name) {} // 'inline' is for convenience only!
  inline std::string asString() const {return _name;} // 'inline' is for convenience only!
};

int main(int argc, char** argv) {
  Elephant Babar("Babar"),Jumbo("Jumbo");
  LIFO<Elephant> zoo;

  zoo.in(Babar);
  zoo.in(Jumbo);
  std::cout << "Jumbo goes out since it is the last-in: " << zoo.out().asString() << std::endl;

  return 0;
}
Rule(s)
Example
#include <stack>
…
std::stack<char> stack_of_characters;

Fundamentals

Default generic types and values

Rule(s)
  • Default effective types or values may be defined using =. At instantiation time, this allows us to avoid listing all effective types and values.
  • Template non-type parameters are substituted by values (instead of effective types) at instantiation time. A value has an integral or enumeration type. It is a pointer or reference to a class object, a pointer or reference to a function, a pointer or reference to a class member function or std::nullptr_t.
Example Heap.Cpp.zip 
// At elaboration time:
template<typename T,int default_capacity = 10,typename Default_representation = std::vector<T> > class Priority_queue { // '#include <vector>'
    private:
        Default_representation _representation;
    public:
        Priority_queue(int capacity = default_capacity) : capacity(capacity) { …

// At instantiation time:
Priority_queue<Task,100,std::deque<Task> > priority_queue; // '#include <deque>'

Generic array

Rule(s)
  • Generic arrays may be used instead of primitive arrays.
Example
std::vector<char> tab(2); // '#include <vector>'
tab[0] = 'a';
tab[1] = 'b';
// tab[2] = 'c'; // Execution error: out of bounds
tab.push_back('c'); // OK, capacity has automatically increased
Example
std::vector<std::string> sentence; // '#include <vector>'
// Matrix of integers (caution: space required between '>' and '>'!):
std::vector<std::vector<int> > matrix; // '#include <vector>'

std::array (C++11)

Rule(s)
  • std::array cumulates the benefit of primitive arrays (fixed sizes) along with the adaptability of STL containers.
  • Array overflow may be controlled (for reliability)… or not (for performance).
Example Palindrome.Cpp.zip 
// '.h' file:
class Palindrome : public std::string {
    …
public: // Something less than '3' -> compilation "error: excess elements in struct initializer"
    constexpr static const std::array<char, 3> Special_characters{' ', '\n', '\t'};
    …
};

// '.cpp' file:
const std::array<char, 3> Palindrome::Special_characters;
…
int out_of_bounds = Palindrome::Special_characters.size();
std::cout << Palindrome::Special_characters[out_of_bounds] << '\n'; // Out of bounds (no control)...
try {
    std::cout << Palindrome::Special_characters.at(out_of_bounds) << '\n'; // Out of bounds (control)...
} catch (std::logic_error& le) { // Inheritance graph: 'std::exception' < 'std::logic_error' < 'std::out_of_range'
    std::cerr << typeid(le).name() << ", " << le.what() << ": " << out_of_bounds << '\n';
}

Generic functions

Rule(s)
  • Beyond its OO status, C++ lets users the possibility of creating functions outside classes (this contrasts with a pure OO style). One may in particular create generic functions.
Example
template<typename T> void my_function(const T&); // Implementation occurs later...
…
char c;
::my_function(c); // Type deduction avoids expanded form: '::my_function<char>(c);'
Rule(s)
  • For historical reasons, C++ offers a lot of predefined reusable and above all powerful generic functions. Their possible use occurs through #include <algorithm> and #include <numeric>.
Example
// Sorting:
short tab[] = {13,7,6,4,12,11,8,3};
std::vector<short> vector(tab,tab + 8);
for(int i = 0;i < vector.size();i++) std::cout << "-" << vector[i];
std::cout << std::endl;
std::sort(vector.begin(),vector.end()); // #include <algorithm>
for(int i = 0;i < vector.size();i++) std::cout << "-" << vector[i];
std::cout << std::endl; 
// Σ:
std::cout << std::accumulate(vector.begin(),vector.end(),0) << std::endl; // #include <numeric>

Mixing inheritance and genericity

Rule(s)
  • The mixing of inheritance and genericity in C++ stumbles over natural (expected) contravariance problems.
Example Inheritance_and_genericity.Cpp.zip 
// '.h' file:
template <typename T> class Garden {
private:
	// 'T' (as second anonymous type) acts as a functor (definition of 'operator()' required in 'T'):
	std::unordered_set <T, T> _garden; 
public:
	Garden(const T&);
};
template <typename T> Garden<T>::Garden(const T& t) { _garden.insert(t); }

class Vegetable { … };
class Cabbage : public Vegetable { … };

// '.cpp' file:
Cabbage cabbage;

Garden<Cabbage> garden(cabbage);
// There is a risk to add carrots for instance, while 'another_garden' refers to a garden of cabbages only:
// Garden<Vegetable>& another_garden = garden; // This *DOES NOT* work (contravariance)...

Garden<Cabbage*> garden_(&cabbage);
// There is a risk to add carrots for instance, while 'another_garden' refers to a garden of cabbages only:
// Garden<Vegetable*>& another_garden_ = garden_; // This *DOES NOT* work (contravariance)...
See also

Advanced features

Generic member function

Rule(s)
  • As of Java, C++11 supports template member functions whose anonymous type(s) are totally independent of those of its enclosing class. Besides, the latter is not necessarily generic.
Example
class Any { 
public:
    template<typename Anonymous> void operator()(Anonymous&);
};

Specialization

Rule(s)
  • Specialization amounts to substituting anonymous types by effective types along with, a priori, an altered behavior.
Example Advanced_genericity.Cpp.zip 
// '.h' file:
template<typename T> void my_function(T& t = std::declval<T>()) {T other = t;};
// Explicit specialization ('T' = 'int') -> *no default value for argument is permitted*:
template<> void my_function(int& t) {int* other = &t;};
// Instantiation (declaration only since body presence means specialization!):
template void my_function(char& t);

// '.cpp' file:
// (Incidental?) overload:
void my_function(char& c) {std::cout << "'char& c' ver.: " << c << std::endl;};
…
// ::my_function(); // Compilation error: 'candidate template ignored: couldn't infer template argument 'T''
char BEL = '\a';
::my_function(BEL); // Existing overload preemption...
::my_function<char>(BEL); // Explicit instantiation ('T' = 'char')
std::string a = "a";
// Or '::my_function<std::string>(a);':
::my_function(a); // Implicit instantiation ('T' = 'std::string')

Template class specialization

Rule(s)
  • Specialization of a template class also amounts to substituting anonymous types by effective types along with inheriting from something, having additional (member) attributes and/or functions, etc.
Example
// '.h' file:
template<typename X> class Is_void : public std::false_type {}; // Base template
// Specialization ('X' anonymous type is substituted for 'void' effective type):
template</* Empty here! */> class Is_void<void> : public std::true_type {};

// '.cpp' file:
std::cout << Is_void<char>::value << '\n'; // '0' meaning 'false' ('value' is a static field of both 'std::false_type' and 'std::true_type')
// Implicit instantiation of specialization:
std::cout << Is_void<void>::value << '\n'; // '1' meaning 'true' 

Alias template

Rule(s)
  • From C++11 there is another way of dealing with typedef.
Example
template<typename X>
using POINTER = X*; // Family of pointers of any type...

template <typename T> void my_function(T t, POINTER<T> pt) { /* … */ }
Example Heap.Cpp.zip 
// '.h' file:
template<typename E>
using Heap_representation_size_type = typename E::size_type;

template<typename T, int default_capacity = 10, typename Default_representation = std::vector<T> > class Priority_queue {
    …
public:
    Heap_representation_size_type<Default_representation> count() const {
        return _representation.size();
    }
    …
};

// '.cpp' file:
Priority_queue<Task, 100, std::deque<Task> > priority_queue;
Task t1(1), t2(2), t3(3);
priority_queue.insert(t1);
priority_queue.insert(t2);
priority_queue.insert(t3);
Heap_representation_size_type<std::deque<Task> > count = priority_queue.count();

Variable template (C++14)

Rule(s)
  • Variables being non-member or member of classes may be made generic on their own.
Example Advanced_genericity.Cpp.zip 
// 'constexpr' is for access at compilation time:
template<typename Number> /* constexpr */ Number Mid = std::numeric_limits<Number>::max() - std::numeric_limits<Number>::min() / static_cast<Number> (2);

template<typename My_anonymous> class My_class {
public:
    // Declaration:
    template<class Number> static const Number Three_key_positive_values;
    static const My_anonymous My_class_property; // Non-template
};
// Definition:
template<typename My_anonymous> template<typename Number> const Number My_class<My_anonymous>::Three_key_positive_values = {std::numeric_limits<Number>::min(), Mid<Number>, std::numeric_limits<Number>::max()};
template<typename My_anonymous> const My_anonymous My_class<My_anonymous>::My_class_property = My_anonymous();

Trailing return type

Rule(s)
  • Genericity benefits from the concomitant use of the decltype operator. In template functions especially, the principle of “trailing return type” is the fact the function's returned type depends upon parameter(s)' type(s).
ExampleConstexpr.Cpp.zip 
// This requires the explicit introduction of 'Result' at instantiation time:
template<typename T, typename Result> Result multiply(T t1, T t2) {
	return t1 * t2;
}
// Compiler fails because 't1' and 't2' are undefined (left-to-right parsing):
// template<typename T> decltype(t1 * t2) multiply(T t1, T t2) {
//	decltype(t1 * t2) t = t1 * t2; // This works here only...
//	return t;
//}
// Trailing return type thanks to 'auto':
template<typename T> /* [] */ auto multiply(T t1, T t2) -> decltype(t1 * t2) {
	return t1 * t2;
}
See also
Standard Template Library (STL) is for many years fully part of C++ while it initially was an external library. STL is mainly constituted of “container” classes, i.e., “collections”, but it also includes “generic” algorithms that may be found in <algorithm> and in <numeric>.
Example of “generic” algorithms
Example of “container” reuse

Specification

Implementation

Example List_map_set.Cpp.zip 
template <typename T> class My_set : public std::set<T> { // Inheritance
    public:
        bool strict_subset(const My_set<T>&);
        My_set<T> operator -(const My_set<T>&);
};
template<typename T> bool My_set<T>::strict_subset(const My_set<T>& s) {
    My_set<T> intersection;
    std::set_intersection(this->begin(),this->end(),s.begin(),s.end(),std::inserter(intersection,intersection.end()));
    return intersection == *this && intersection != s;
}   
template<typename T> My_set<T> My_set<T>::operator -(const My_set<T>& s) {
    My_set<T> difference;
    std::set_difference(this->begin(),this->end(),s.begin(),s.end(),std::inserter(difference,difference.end()));
    return difference;
}
C++ sequences offer key facilities over native arrays. Typically, the std::vector<T> class owns the push_back function, which automatically expands the capacity of arrays while native arrays have to be manually reallocated by means of the delete[] and new C++ operators.
Example
// '.h' file:
class Prisoner {
…
    std::list<const Criminal_case*> _all_criminal_cases;
…

// '.cpp' file:
// Adding at the end:
void Prisoner::involve(const Criminal_case& criminal_case) {
    _all_criminal_cases.push_back(&criminal_case);
}
// First alternative, adding at the beginning:
void Prisoner::involve(const Criminal_case& criminal_case) {
    _all_criminal_cases.push_front(&criminal_case);
}
// Getting the last one:
const Criminal_case* Prisoner::last() const {
    return _all_criminal_cases.empty() ? NULL : _all_criminal_cases.back();
}

Other C++ sequences

Example
std::queue<char,std::list<char> > q;
q.push('a');
q.push('b');
q.pop();
std::cout << "front: " << q.front() << std::endl; // 'b' is displayed
See also
C++ sets are accessible via the #include <set> or #include <unordered_set> macro-statements.

std::set

Rule(s)
Example List_map_set.Cpp.zip 
std::set<char> alphabet; // This is equivalent to: 'std::set<char,std::less<char> > alphabet;' 
alphabet.insert('a');
alphabet.insert('a'); // Without effect because 'a' < 'a' is 'false'
assert(alphabet.size() == 1);
Alternative (this requires the redefinition of the > operator in the Task class):
std::set<Task,std::greater<Task> > scheduler;
Creating sets from native arrays and searching in sets:
short tab[] = {3,4,6,7,8,11,12,13};
std::set<short> set(tab,tab + 8);
assert(std::binary_search(set.begin(),set.end(),13)); // '#include <algorithm>'
assert(! std::binary_search(set.begin(),set.end(),14)); // '#include <algorithm>'

std::unordered_set (C++11)

Rule(s)
Example Inheritance_and_genericity.Cpp.zip 
// '.h' file:
template <typename T> class Garden {
private:
	// 'T' (as second anonymous type) acts as a functor (definition of 'operator()' required in 'T'):
	std::unordered_set <T, T> _garden; 
public:
	Garden(const T&);
};
template <typename T> Garden<T>::Garden(const T& t) { _garden.insert(t); }

class Vegetable {
    public:
        std::size_t operator()(const Vegetable& vegetable) const {
            // Hash on several fields uses '^': https://www.techiedelight.com/use-pair-key-std-unordered_set-cpp/
            std::hash<std::bitset<sizeof (Vegetable*)> > hash;
            return hash(reinterpret_cast<uintptr_t> (&vegetable)); // Storage relies on memory address!
        }
    …
};
class Cabbage : public Vegetable { … };

// '.cpp' file:
Garden<Cabbage> garden(cabbage{});
See also
C++ maps are accessible via the #include <map> macro-statement for common maps and multi-maps that allow shared keys. Moreover, unordered maps and unordered multi-maps are introduced from C++11 (#include <unordered_map>).
Examples (how to represent the 5x2 - 3x + 8 polynomial without maps?)
double polynomial[] = {8.,-3.,5.} // First possibility… -> bad idea
std::list<std::pair<int,double> > polynomial; // Second possibility… -> fairly bad idea
Rule(s)
Example (how to represent the 8x39 - 12x10 polynomial with maps?
std::map<int,double> polynomial;
polynomial[39] = 8.;
polynomial[10] = -12.;
Example (unshared key)
// Equivalent to 'std::map<std::string,std::string,std::less<std::string> > given_names__dictionary;':
std::map<std::string,std::string> given_names__dictionary; 
std::string s1 = "Franck";
std::string s2 = "Franck";
given_names__dictionary[s1] = "English origin given name"; given_names__dictionary[s2] = "German origin given name"); assert(given_names__dictionary.size() == 1);
Example (shared key, i.e., multi-maps)
std::multimap<std::string,std::string> given_names__dictionary;
std::string s1 = "Franck";
std::string s2 = "Franck";
given_names__dictionary[s1] = "English origin given name";
given_names__dictionary[s2] = "German origin given name");
assert(given_names__dictionary.size() == 2);

Unordered maps

Rules
Example (unordered map) Polynomial.Cpp.zip 
'.h' file:
class Polynomial {
private:
    std::unordered_map<int, double> _polynomial;
public:
    Polynomial(const std::initializer_list<std::unordered_map<int, double>::value_type>&);
    const Polynomial& operator=(const Polynomial&);
};

'.cpp' file:
Polynomial::Polynomial(const std::initializer_list<std::unordered_map<int, double>::value_type>& members) {
    _polynomial.insert(members);
    // Longer:
    /* for (std::unordered_map<int, double>::value_type member : members) _polynomial.insert(member); */
}
const Polynomial& Polynomial::operator=(const Polynomial& p) {
    if (this != &p) {
        _polynomial.clear();
        std::copy(p._polynomial.begin(), p._polynomial.end(), std::inserter(_polynomial, _polynomial.begin()));
    }
    return *this;
}
int main(int argc, char** argv) {
    Polynomial p{ {39, 8.}, {10, -12.} }, q{ {1, 1.} };
    q = p;

    return 0;
}
See also
Iterators
Example List_map_set.Cpp.zip 
std::list<const Task*> l;
assert(l.empty());
l.push_front(&t1); // t1
l.push_front(&t2); // t2 t1
l.push_front(&t3); // t3 t2 t1
l.push_front(&t4); // t4 t3 t2 t1
l.insert(l.begin(), &t5); // t5 t4 t3 t2 t1
l.push_back(&t1); // t5 t4 t3 t2 t1 t1
assert(l.size() == 6);

std::list<const Task*>::iterator j;
for (j = l.begin(); !(j == l.end()); j++) std::cout << "- " << (*j)->start() << '\t';

std::list<const Task*>::iterator where_is_t2 = std::find(l.begin(), l.end(), &t2);
std::cout << "Task 't2': " << (*where_is_t2)->start() << std::endl;

std::reverse(l.rbegin(), l.rend()); // t1 t1 t2 t3 t4 t5
for (j = l.begin(); !(j == l.end()); j++) std::cout << "- " << (*j)->start() << '\t';

std::list<const Task*>::reverse_iterator k;
for (k = l.rbegin(); !(k == l.rend()); k++) std::cout << "- " << (*k)->start() << '\t';

l.sort(); // Pointers order: t5 t4 t3 t2 t1 t1
for (j = l.begin(); !(j == l.end()); j++) std::cout << "- " << (*j)->start() << '\t';

l.unique(); // t5 t4 t3 t2 t1 (remove only consecutive elements?) 
for (j = l.begin(); !(j == l.end()); j++) std::cout << "- " << (*j)->start() << '\t';
C++11 comes with a simplified possibility of iterating on collections without the explicit introduction of “cursors” like iterators, etc.
Example
for (char c : string) { // 'string' has 'std::string' type…
Rule(s)
Example
std::unordered_multimap<std::string, std::string> situation_of_French_2012_presidential_election {
    {"Macron", "President"},
    {"Macron", "Candidate"},
    {"Philippe", "Prime minister"},
    {"Mélanchon", "Challenger"},
    {"Mélanchon", "Candidate"},
    {"Le Pen", "Challenger"},
    {"Le Pen", "Candidate"}};
for (auto&& [name, role] : situation_of_French_2012_presidential_election) { // Binding (C++17)
    std::cout << name << " as " << role << std::endl;
}
See also
C++ priority queues (a.k.a. heaps) are backed by arrays whose management is comparable to a rooted tree.
Internal representation
Heap internal representation
Example (creation)
short tab[] = {3,4,6,7,8,11,12,13};
std::vector<short> my_heap(tab,tab + 8);
std::make_heap(my_heap.begin(),my_heap.end());
for(int i = 0;i < my_heap.size();i++) std::cout << "-" << my_heap[i];
Example (heap sort)
std::sort_heap(my_heap.begin(),my_heap.end());
for(int i = 0;i < my_heap.size();i++) std::cout << "-" << my_heap[i];
Heap sort (1/2)
Heap sort (2/2)
Heap sort result (the array and the binary tree are no longer organized as a heap!)
Heap sort result
Resource(s)
See also
Red-black trees

For example, std::set<Key,Compare> objects are based on red-black trees. Please note that std::rb_tree<…> is a native STL generic class, but it is not member of C++ collections in the sense that it does not aim at being directly (re)-used.

Resource(s)
Exception management is a programming style that favors the implementation of a defense strategy when facing up abnormal behaviors, failures or, worst, stronger errors that may come from the Operating System (OS) itself (e.g., no more memory). Promoted by Ada, exception management relies on a self-contained thread of control compared to the “normal” program execution. Exceptions are raised and caught depending upon the chosen defense strategy. In OO programming, exceptions are plain objects and, in C++, they benefit from being instantiated from a predefined (extensible) hierarchy of classes.
Rule(s)

Reinforcing the exception system with noexcept

Rule(s)
Example Exception_management.Cpp.zip 
void callee() noexcept(false); // Equivalent declaration: 'void callee();'
void caller() noexcept(true) {
    ::callee(); // No compilation error...
    // throw "Something while 'noexcept(true)'"; // Compilation error...
};
Rule(s)
Example Exception_management.Cpp.zip 
template<typename T> T my_function() noexcept(sizeof(T) < 4);
…
// Instantiation of 'my_function' with 'T' = 'void'
decltype(::my_function<void>()) *p; // Compilation error because 'sizeof(void)'

Creating new exception types

Rule(s)
Example Exception_management.Cpp.zip 
class Invalid_temperature_exception : std::exception { // '#include <stdexcept>'
    float _value; // In Celsius
public:
    Invalid_temperature_exception(float);
    float value() const;
    const char* what() const noexcept(true) final; // No exception can be thrown!
};

Declaring and throwing exceptions

Example Exception_management.Cpp.zip 
// '.h' file:
class Temperature {
public:
    enum class Temperature_unit : char /* 'char' -> integral type is required! */ {
        Celsius = 'C', Fahrenheit = 'F', Kelvin = 'K'
    };
    static const float Min;
private:
    float _value; // In Celsius
    float _step;
public:
    float asCelsius() const;
    float asFahrenheit() const;
    float asKelvin() const;
    void increment() noexcept(true);
    void decrement() noexcept(false);
    int operator<(const Temperature&) const;
    int operator<=(const Temperature&) const;
    int operator>(const Temperature&) const;
    int operator>=(const Temperature&) const;
    Temperature();
    Temperature(float, Temperature_unit = Temperature_unit::Celsius) noexcept(false);
};

// '.cpp' file:
void Temperature::decrement() noexcept(false) { // Potential throwing...
    _value -= _step;
    if (_value < Min) throw _value; // Effective throwing...
}
…
Temperature::Temperature(float value, enum Temperature_unit unit) noexcept(false) {
	switch (unit) {
        case Temperature_unit::Celsius: _value = value;
            break;
        case Temperature_unit::Fahrenheit: _value = (value - 32.F) * 5.F / 9.F;
            break;
        case Temperature_unit::Kelvin: _value = value + Min;
            break;
        default: throw "Illegal temperature unit";
    }
    if (_value < Min) throw Invalid_temperature_exception(_value);
    _step = 0.0001F;
}

Global management policy setup

Example Exception_management.Cpp.zip 
// '.h' file:
class Global_exception_management {
public:
    static void my_unexpected();
    static void my_terminate();
};

// '.cpp' file:
void Global_exception_management::my_unexpected() {
    std::cerr << "my_unexpected" << std::endl; // Partial exception processing
// Active exception is re-routed.
// This creates a chain so that an instance of 'std::bad_exception' is thrown whether the failing function has this type in its signature
    throw; 
}

void Global_exception_management::my_terminate() {
    std::cerr << "my_terminate" << std::endl; // For test only
}

std::set_unexpected(&Global_exception_management::my_unexpected);
std::set_terminate(&Global_exception_management::my_terminate);

Catching exceptions (through references for polymorphism)

Example Exception_management.Cpp.zip 
std::exception_ptr pe; // C++11
try {
// Instance of 'Invalid_temperature_exception' may potentially be raised (or "Illegal temperature unit"):
    Temperature t(0.F, Temperature::Temperature_unit::Kelvin);
    t.decrement(); // Value of 'float' *IS* raised...
} catch (const char* e) { // Matches 'throw "Illegal temperature unit"'
    std::cerr << "const char*: " << e << std::endl;
} catch (Invalid_temperature_exception& ite) { // Matches 'throw Invalid_temperature_exception(_value)'
    std::cerr << ite.what() << std::endl;
}    //catch (float& e) { // Matches 'throw _value' 
//	std::cerr << "float&: " << e << std::endl;
//}
catch (std::bad_exception& be) { // 'Global_exception_management::my_unexpected' is called before
    std::cerr << "be: " << be.what() << std::endl;
} catch (...) {
    std::cerr << "Default management" << std::endl;
    pe = std::current_exception(); // C++11
}
try {
    if (pe) std::rethrow_exception(pe);
}
// Great caution: missing 'throw _value':
catch (const std::exception& e) {
    std::cout << "Caught exception \"" << e.what() << "\"\n";
}
See also
Covariance (on return types) in C++ involves, as polymorphism, pointers (or references).
Example (no covariance) Covariance.Cpp.zip 
// 'Covariance.h' file
#ifndef _Covariance_H
#define _Covariance_H

class Human_being {
public:
    virtual const Human_being cloning() const;
};

class Man : public Human_being {
public:
    const Man cloning() const; // Compilation error: virtual function 'cloning' has a different return type ('const Man') than the function it overrides (which has 'const Human_being' as return type)
};

class Woman : public Human_being {
public:
    const Woman cloning() const; // Same type of compilation error
};

#endif	/* _Covariance_H */
Example (covariance) Covariance.Cpp.zip 
// 'Covariance.h' file
#ifndef _Covariance_H
#define _Covariance_H

#include <iostream>

class Human_being {
public:
    virtual const Human_being* cloning() const;

    virtual ~Human_being() {
        std::cout << "Human_being";
    }
};

class Man : public Human_being {
public:
    const Man* cloning() const;

    ~Man() {
        std::cout << "-Man";
    }
};

class Woman : public Human_being {
public:
    const Woman* cloning() const;

    ~Woman() {
        std::cout << "-Woman";
    }
};

#endif	/* _Covariance_H */
// 'Main.cpp' file
#include <iostream>

#include "Covariance.h"

const Human_being* Human_being::cloning() const {
    std::cout << "'cloning()' in 'Human_being' is called…\n";
    return new Human_being; // Very bad programming because 'delete' must be later called in calling context
}

const Man* Man::cloning() const {
    std::cout << "'cloning()' in 'Man' is called…\n";
    return new Man; // Very bad programming because 'delete' must be later called in calling context
}

const Woman* Woman::cloning() const {
    std::cout << "'cloning()' in 'Woman' is called…\n";
    return new Woman; // Very bad programming because 'delete' must be later called in calling context
}

int main(int argc, char** argv) {
    const Human_being *const FranckBarbier = new Man;
    const Human_being* clone = FranckBarbier->cloning(); // 'cloning()' in 'Man' is called… => covariance, yes!
    delete clone;
    delete FranckBarbier;

    return 0;
}
See also
Like many other languages (Java, JavaScript, Python…), C++ allows the possibility of having a variable number of arguments for a function (a.k.a. “variadic” function).

Variadic function

Example Variadic.Cpp.zip 
// 'Variable_number_of_arguments.h' file
#ifndef _Variable_number_of_arguments_H
#define _Variable_number_of_arguments_H

#include <time.h>

#include <set>

class Human_being {
private:
    tm _birth_date;
public:
    Human_being(int = 01, int = 01, int = 1970);
private:
    std::set<Human_being*> _children;
public:
    void births(Human_being*…); // '…' means that the number of arguments is variable (first style)
    void births(int, Human_being*…); // '…' means that the number of arguments is variable (second style)
};

#endif	/* _Variable_number_of_arguments_H */
// 'Main.cpp' file
#include <cstdarg> // 'va_list' type
#include <cstdlib> // 'NULL'

#include "Variable_number_of_arguments.h"

using namespace std;

Human_being::Human_being(int day_of_month, int month, int year) {
    _birth_date.tm_mday = day_of_month;
    _birth_date.tm_mon = month;
    _birth_date.tm_year = year;
}

void Human_being::births(Human_being* child…) { // '…' means that the number of arguments is variable
    va_list children;
    va_start(children, child);
    for (Human_being* e = child; e != NULL; e = va_arg(children, Human_being*)) _children.insert(e);
    va_end(children);
}

void Human_being::births(int nb, Human_being* child…) { // '…' means that the number of arguments is variable
    va_list children;
    va_start(children, child);
    Human_being* e = child;
    for (int i = 0; i < nb; i++, e = va_arg(children, Human_being*)) _children.insert(e);
    va_end(children);
}

int main(int argc, char** argv) {
    Human_being FranckBarbier(11, 01, 1963);
    FranckBarbier.births(new Human_being(6, 12, 1993), new Human_being(15, 4, 1996), new Human_being(22, 2, 2001), NULL);
    FranckBarbier.births(3, new Human_being(6, 12, 1993), new Human_being(15, 4, 1996), new Human_being(22, 2, 2001));
    return 0;
}

Variadic template

Rule(s)
Example (definition as member function in .h file) Variadic.Cpp.zip 
class Human_being {
…
public: // Must be 'public:' when called with one argument (direct call!):
    template <typename Child> void variadic_births(Child child) { // Base case...
        // Template member function in essence allows 'this':
        this->_children.insert(child); // This ends recursion...
    }
    template<typename Child, typename... Children> void variadic_births(Child child, Children... children) { // "Parameter pack"
        this->variadic_births(child);
        this->variadic_births(children...); // Unpack
    };
…
};
Example (definition as non-member function in .h file) Variadic.Cpp.zip 
class Human_being {
…
};
namespace variadic_template {
    template <typename T> void births(T& parent, T* child) { // Possible simplification: 'parent' and 'child' come from the same type
        // Constraints on 'T' is powered from C++20 (https://en.cppreference.com/w/cpp/language/constraints)
        static_assert(std::is_base_of<Human_being, T>::value, "Type parameter of this class must derive from 'Human_being'");
        parent.insert(child); // Call of member function to access '_children'...
    }
    template<typename T, typename... Children> void births(T& parent, T* child, Children... children) {
        static_assert(sizeof... (Children) > 0, "Never inferred with '0' arguments, end of unpacking...");
        // Constraints on 'T' is powered from C++20 (https://en.cppreference.com/w/cpp/language/constraints)
        static_assert(std::is_base_of<Human_being, T>::value, "Type parameter of this class must derive from 'Human_being'");
        births(parent, child);
        births(parent, children...); 
    }
}
Example (usage in .cpp file) Variadic.Cpp.zip 
Human_being s(28, 07, 1964);
// s.variadic_births(); // As expected, compilation error...
s.variadic_births(o.get(), l.get(), j.get());
std::cout << "s: " << s.count() << std::endl;
// As non-member function:
variadic_template::births(s, o.get(), l.get(), j.get()); // No effect because of 'std::set'

Variadic template and lambda expression

Example Lambda_expression.Cpp.zip 
'.h' file:
template<typename Cumulative, typename... Cumulatives>
  Cumulative Cumulate(Cumulative const& init, Cumulatives const&... cumulatives) {
    std::array<Cumulative, sizeof...(cumulatives) + 1 > my_array{init, cumulatives...}; // C++20: 'auto my_array = std::to_array(init,cumulatives...);'
    // Simple example of STL iterators' usage:
    return std::accumulate(std::next(my_array.begin()), my_array.end(), *my_array.begin());
}

template<typename... Cumulatives>
  auto Cumulate_to_illustrate_lambda_expression(Cumulatives... cumulatives) {
    return [cumulatives...] () noexcept {
        return ::Cumulate(cumulatives...);
    }(); // Arrrggglll, immediate call...
}

/* Transform 'std::array' into pack... */
// C++14, 'std::index_sequence<I...>
template<typename T, std::size_t N, std::size_t... I> auto _std__array_to_pack(const std::array<T, N>& my_array, std::index_sequence<I...>) {
    return ::Cumulate(my_array[I]...);
}
// C++14, 'std::make_index_sequence<N>' -> 0, 1... N-1
template<typename T, std::size_t N, typename Indices = std::make_index_sequence<N> > auto std__array_to_pack(const std::array<T, N>& my_array) {
    return _std__array_to_pack(my_array, Indices());
}

'.cpp' file:
// 'é' as 'char' creates a (non-surprising) conflict between "Cumulative" and "Cumulatives"
    std::cout << "::Cumulate(std::string(1, e.character),\"é\",\"è\",\"ê\"): "
            // C++17 allows the inference of types between '<>':
            << ::Cumulate/*<std::string,std::string>*/(std::string(1, e.character), "é", "è", "ê") << std::endl;

    /* Test of transform 'std::array' into pack... */
    std::array<std::string, 4U> my_array{{"e", "é", "è", "ê"}};
    // Instantiation: T=std::string; N=4U; Indices=__make_integer_seq_alias<std::integer_sequence, unsigned int, 4U>
    std::cout << "std__array_to_pack(my_array): " << ::std__array_to_pack(my_array) << std::endl; // This calls '::Cumulate'

    std::cout << "Cumulate_to_illustrate_lambda_expression(std::string(1, e.character),\"é\",\"è\",\"ê\"): "
		<< ::Cumulate_to_illustrate_lambda_expression(std::string(1, e.character), "é", "è", "ê") << std::endl;

Fold

Example Lambda_expression.Cpp.zip 
template<typename Cumulative, typename... Cumulatives>
  Cumulative Cumulate(Cumulative const& init, Cumulatives const&... cumulatives) {
    std::array<Cumulative, sizeof...(cumulatives) + 1> my_array{init, cumulatives...}; // C++20: 'auto my_array = std::to_array(init,cumulatives...);'
	// C++17 fold:
	return (cumulatives + ... + init);
}
See also
Type conversion (a.k.a. casting) is a crucial task in daily programming since the robustness of the C++ typing system depends on casting variables that really conform to each other based on their declared types. Strict control of type conversion relies on operators, and possibly further implementation of type-to-type interoperability.

Type interoperability

Rule(s)
Example
'.h' file:
class My_class {
    public:
        explicit My_class(int);
    …
};

'.cpp' file:
My_class::My_class(int i) { /* Some code... */ }
…
My_class mc0 = 0; // Compilation error comes from 'explicit'

Aware casting

Rule(s)
Example (static_cast)
Any* my_pointer = (Any*)pointer;  
// Any* my_pointer = static_cast<Any*>(pointer); // Compilation error
Example (const_cast)
// '.h' file:
class Person : … {
public:
    const std::string identity;
    …

// '.cpp' file:
Person& Person::operator=(Person const& p) {
    const_cast<std::string&>(this->identity) = p.identity; // Assignment overriding justifies this!
    …
Example ( dynamic_cast)
Animal* a = new Cat;
// Cat* c = a; // Compilation error resulting from static checking...
try {
    Cat* c = dynamic_cast<Cat*>(a);
} catch (std::bad_cast& bc) {
    std::cerr << bc.what() << '\n';
    // Try repairing here...
}

Towards safer conversions

Rule(s)
Example Advanced_genericity.Cpp.zip 
// '.h' file:
class Male;

class Female { // 'explicit' is used for Male conversion
public:
    const std::string identity;
    inline Female(const std::string& identity) : identity(identity) {};
// Common conversion (transgender):
    explicit operator Male() const; // Refuse (implicit) 'f = m;' provided that assignment is supported as well...
// Template member function (from C++11):
    template<typename Specie> explicit operator Specie() const { // Conversion to 'Specie', refuse "implicit"
        return Specie();
    };
};

class Male { // 'explicit' *IS NOT* used for Female conversion
public:
    const std::string identity;
    inline explicit Male(const std::string& identity) : identity(identity) {}; // Refuse (implicit) 'Male = "FranckBarbier";'
// Common conversion (transgender):
    operator Female() const; // Accept (implicit) 'm = f;' provided that assignment is supported as well...
// Template member function (from C++11):
// g++ *REQUIRES* 'explicit' (compilation error) while Visual Studio doesn't:
    template<typename Specie> operator Specie() const { // Conversion to 'Specie', accept "implicit"
        return Specie();
    };
};

class Minotaur {
public:
    const std::string identity;
    inline Minotaur(const std::string& identity) : identity(identity) {};
};
// Explicit specialization for 'Minotaur':
template<> Male::operator Minotaur() const { // Because 'Specie()' cannot work...
    return Minotaur(identity);
}

class Medusa {/* Snake woman */}; // Default no-argument constructor to match to 'Specie()'
class Sphinx {/* Lion woman */};
// Explicit instantiation for 'Sphinx':
template Female::operator Sphinx() const; // Useless anyway because no body...

// '.cpp' file:
Female::operator Male() const {
    return Male(identity);
}
Male::operator Female() const {
    return Female(identity);
}
…
Male Adam("XY");
Female Eve("XX");
static_cast<Male> (Eve); // Use debugger to enter into 'explicit Female::operator Male() const'
static_cast<Female> (Adam); // Use debugger to enter into 'Male::operator Female() const'
static_cast<Minotaur> (Adam); // Use debugger to enter into 'template<> Male::operator Minotaur() const'
static_cast<Medusa> (Eve); // Use debugger to enter into 'template<typename Specie> explicit operator Specie() const'

Introspection based on Run Time Type Information (RTTI)

Rule(s)
Example RTTI.Cpp.zip 
Activity_card_computation<int>* pacc;
Activity_card_comp_quad<int> accq, *paccq;
paccq = &accq; // Same type...
pacc = &accq; // Inheritance conformance

// paccq = static_cast<Activity_card_comp_quad<int>*> (pacc); // Compilation error

paccq = reinterpret_cast<Activity_card_comp_quad<int>*> (pacc); // Unreliable, but this works at run-time because 'pacc' points to an instance of 'Activity_card_comp_quad<int>'
const std::type_info& ti1 = typeid (paccq); // Effective type is computed based on the 'typeid' operator ('#include <typeinfo>')
if (ti1 != typeid (Activity_card_comp_quad<int>*)) throw std::bad_typeid(); // Exception type through '#include <typeinfo>'
std::cout << ti1.name() << std::endl;

paccq = dynamic_cast<Activity_card_comp_quad<int>*> (pacc); // Reliable because conversion occurs if and only if types comply with each other
const std::type_info& ti2 = typeid (paccq);
if (ti2 != typeid (Activity_card_comp_quad<int>*)) throw std::bad_typeid();
std::cout << ti2.name() << std::endl;
See also
Type checking programming languages like C++ require type declaration. Type inference is the ability to deduce the type of a variable, reducing verbose type declaration.

auto keyword

Rule(s)
Example
auto x = 0; // 'x' has type 'int' because '0' is by default of type 'int'
auto c = 'a'; // 'char'
auto d = 0.5; // 'double'
auto national_debt = 14400000000000LL; // 'long long'

decltype keyword

Rule(s)
Example N_INSEE.Cpp.zip 
N_INSEE FB("1630125388055");
decltype(FB) JBD("1010264445244");
Example Type_inference.Cpp.zip 
void f() {}
…
// Type of 'f':
std::cout << "typeid(decltype(::f)): " << typeid(decltype(::f)).name() << std::endl;
// Returned type of 'f', i.e., 'void':
std::cout << "typeid(decltype(::f())): " << typeid(decltype(::f())).name() << std::endl;
Rule(s)
Example
Person p("FranckBarbier");
// 'decltype(p.identity)' -> 'std::string' while 'decltype((p.identity))' -> 'std::string'
// Compilation error (remove comments, remove error):
// decltype((p.identity)) id /* = p.identity */; 
// std::cout << "typeid(id): " << typeid(id).name() << std::endl;
Rule(s)
Example Type_inference.Cpp.zip 
void g(const std::string& identity) { /* ... */ }
…
// Compilation error -> problem simply comes from an absence of argument:
// std::cout << "typeid(decltype(::g())): " << typeid(decltype(::g())).name() << std::endl;
std::cout << "typeid(decltype(::g(std::string&))): " << typeid(decltype(::g("Fictitious string!"))).name() << std::endl; // OK!
std::cout << "typeid(decltype(::g(std::string&))): " << typeid(decltype(::g(std::declval<const std::string&>()))).name() << std::endl; // Even better!
Example Smart_pointers.Cpp.zip 
std::unordered_map<std::string, std::unique_ptr<Mammoth>&&> zoo; // Indexed access based on names...
std::cout << std::boolalpha <<
    std::is_same_v<decltype(zoo)::value_type, std::pair<const std::string, std::unique_ptr<Mammoth>&&> > << std::endl; // 'true'
decltype(zoo)::iterator i = zoo.begin(); // So, '*i' is a pair...
auto&& value = (*i).second; // Type of 'value' is 'std::unique_ptr<Mammoth>&' and *NOT* 'std::unique_ptr<Mammoth>&&':
static_assert(std::is_same_v<decltype(value), std::unique_ptr<Mammoth>&>, "Type checking failed, why?");
See also

Structured binding

Rule(s)
Example Lambda_expression_gcc.Cpp.zip 
'.h' file:
class Person {
public:
    const std::string _given_name;
    const std::string _surname;
    std::string _nickname;
    inline explicit Person(const std::string& given_name, const std::string& surname, const std::string& nickname) : _given_name(given_name), _surname(surname), _nickname(nickname) {
    }
};

'.cpp' file:
char given_name[] = {'f', 'r', 'a', 'n', 'c', 'k'};
// Binding requires 6 items:
auto [f, r, a, n, c, k] = given_name; // Copy 'given_name[i]' into 'f', 'r'...
assert(f == 'f');

Person p("Franck", "Barbier", "?");
auto& [gn, sn, nn] = p; // References to p's (public only!) data...
assert(gn.compare("Franck") == 0);
assert(sn.compare("Barbier") == 0);
nn = "Bab";
std::cout << p._nickname << std::endl; // 'Bab'
// If argument of 'decltype' is a non-parenthesized id-expression naming a structured binding,
// then 'decltype' yields the referenced type:
static_assert(std::is_same<decltype(nn), std::string>::value);
static_assert(std::is_same<decltype((nn)), std::string&>::value);
C++ supports the notion of function pointer by which any function may be called through a pointer instead of its name. C++11 extends the principle by means of the std::function mechanism.

Class member pointer

Rule(s)
Example Function_pointer.Cpp.zip 
// '.h' file:
class Meal {
public:
    static const std::tm Defaut_moment; '#include <ctime>'
    enum Meal_type {
        Breakfast, Lunch, Afternoon_tea, Dinner
    };
private:
    enum Meal_type _type;
    std::tm _moment;
public:
    Meal(enum Meal_type = Breakfast, const std::tm& = Defaut_moment);
    const std::tm& moment() const;
// It's useful to setup the type of the member function:
    typedef const std::tm& (Meal::*Moment_type)() const;
};

// '.cpp' file:
const std::tm Meal::Defaut_moment = {0, 0, 12, 15, 3, 96}; // April 15, 1996

Meal::Meal(enum Meal_type type, const std::tm& moment) : _type(type), _moment(moment) {}

const std::tm& Meal::moment() const {return _moment;}

int main(int argc, char** argv) {
    time_t clock = std::time(&clock);
    std::tm* now = std::gmtime(&clock);
    Meal m1(Meal::Dinner, *now);
    std::cout << "m1 at " << std::asctime(&(m1.moment())) << "\n\n";
    Meal m2;
    std::cout << "m2 at " << std::asctime(&(m2.moment())) << "\n\n";

    const std::tm& (Meal::*function_pointer)() const; // Pointer declaration
    function_pointer = &Meal::moment; // Pointer assignment
    const std::tm moment = (m1.*function_pointer)(); // Pointer use
    std::cout << "m1 at " << std::asctime(&(moment)) << "\n\n";

    char* (*pointer_asctime)(const std::tm*); // Pointer declaration
    pointer_asctime = &std::asctime; // Pointer assignment
    std::cout << "m2 at " << (*pointer_asctime)(&(m2.moment())) << "\n\n"; // Pointer use

    return 0;
}
Rule(s)
Example Function_pointer.Cpp.zip 
Meal::Moment_type function_pointer_ = function_pointer; // 'typedef const std::tm& (Meal::*Moment_type)() const;'
std::function<const std::tm& (const Meal&)> function_pointer__ = function_pointer;
Example N_INSEE.Cpp.zip 
// '.h' file:
class N_INSEE {
// 'true' in all cases since 'sizeof(long long) >= 8':
    static_assert(sizeof(long long) > 4, "'sizeof(long) == 4' imposes the use of 'long long'");
    long long _valeur;
public:
    N_INSEE(const std::string&);
    int clef() const;
};

// '.cpp' file(s):
N_INSEE FB("1630125388055"); // Clef -> '29'
std::cout << "Key of 1630125388055 is equal to: " << FB.clef() << std::endl;
// long long N_INSEE::*p_valeur = &N_INSEE::_valeur; // Compilation error: pointers on class members require 'public:'
int (N_INSEE::*p_clef) () const = &N_INSEE::clef;
std::cout << "Key of 1010264445244 is equal to: " << std::invoke(p_clef, FB) << std::endl; // C++17: '#include <functional>'
C++ supports the notion of lambda expression that is similar to that of “function object” or functor. Simply speaking, functors are common objects that support the redefinition of the () operator, i.e., “the call” of a function. Lambda expressions are anonymous one-shot functions that support a compact (dedicated) syntax.

Functor

Rule(s)
Example Lambda_expression.Cpp.zip 
// '.h' file:
class Substituable_character { 
    private:
        std::unordered_set<char> _substitutes;
    public: // 'inline' is for pedagogical reasons *ONLY* (compactness of code)
        const char character;
        inline Substituable_character(char character, std::initializer_list<char> substitutes) : character(character) {
            for (auto substitute : substitutes) _substitutes.insert(substitute);
        }
        // Functor (later) used by 'std::transform' ('()' operator can take as many parameters as desired):
        inline const char operator() (char substitute) const { // '()' operator contextual definition
            if (_substitutes.find(substitute) == _substitutes.end()) return substitute;
            return character;
        }
        …
};

class Palindrome_word {
    private:
        std::string _word;
    public:
        inline Palindrome_word(const std::string& word) : _word(word) {} // 'inline' is for pedagogical reasons *ONLY* (compactness of code)
        void alter(const Substituable_character&);
        …
};

// '.cpp' file:
void Palindrome_word::alter(const Substituable_character& sc) {
    std::transform(_word.begin(), _word.end(), _word.begin(), sc); // 'sc' object is viewed as functor...
}
…
Substituable_character a('a', { 'à' }); // Aggregate initialization
Substituable_character e('e', { 'é', 'è', 'ê'}); // Aggregate initialization
Substituable_character u('u', { 'ù' }); // Aggregate initialization
// Etc.
std::cout << a.operator()('à') << std::endl; // 'a'
Palindrome_word pw("élu");
pw.alter(e);
std::cout << pw.toString() << std::endl; // 'elu'

Lambda expression

Rule(s)
Example (on the fly) Lambda_expression.Cpp.zip 
// '.h' file:
class Substituable_character {
    private:
        std::unordered_set<char> _substitutes;
    public:
        …
        std::string toString() const;
};

// '.cpp' file:
std::string Substituable_character::toString() const {
    std::string result(1, character);
    // Lambda expression ('&' allows the injection of local variables, e.g., 'result' by reference):
    std::for_each(_substitutes.begin(), _substitutes.end(), [&](char substitute) /* -> void */ {
        result += "-" + std::string(1, substitute);
    });
    return result;
}
Example (lambda expression is stored as a common object) Lambda_expression.Cpp.zip 
// '.h' file:
class Palindrome_word {
    private:
        std::string _word;
    public:
        inline Palindrome_word(const std::string& word) : _word(word) {} // 'inline' is for pedagogical reasons *ONLY* (compactness of code)
        void alter(const Substituable_character&);
        void alter_(const Substituable_character&);
        …
};
                    
void Palindrome_word::alter_(const Substituable_character& sc) {
    auto my_lambda = [sc](char substitute) /* -> const char */ {
        // By lazyness, one calls 'const char operator() (char substitute) const' in 'Substituable_character':
        return sc(substitute);
    };
    std::transform(_word.begin(), _word.end(), _word.begin(), my_lambda); // Lambda expression instead of explicit functor...
}

Capture

Example (capture by reference versus by value) Lambda_expression_.Cpp.zip 
std::string FB = "Franck Barbier";
char my_char = 'a', number_of_my_char = 0;
// Injecting one object by copy and the other one by reference:
std::for_each(FB.begin(), FB.end(), [my_char, &number_of_my_char] (const char& c) /* -> bool */ {
    if (c == my_char) {
        number_of_my_char++;
        return true;
    }
    return false;
});
assert(number_of_my_char == 2); // Two occurrences of 'a'

mutable keyword

Rule(s)
  • mutable means that the redefinition of the () operator is no longer const. Deeply speaking, a capture-by-copy object is a member attribute in an instance of the closure type.
Example (reminder on mutable) Lambda_expression_.Cpp.zip 
'.h' file:
class Illustration_of_mutable {
    int _a;
    mutable int _b;
    void object_state_is_not_changed() const;
};

'.cpp' file:
void Illustration_of_mutable::object_state_is_not_changed() const {
    //    _a++; // Compilation error due to 'const'
    _b++; // 'mutable' inhibits 'const'
}
Example (mutable) Lambda_expression_.Cpp.zip 
std::string FB = "Franck Barbier";
char from = 'a', to = 'A';
bool changed = false;
auto my_mutable_functor = [from, to, changed](char& c) mutable {
    if (c == from) {
        c = to;
        changed = !changed; // Requires 'mutable'...
    }
    return changed;
};
std::for_each(FB.begin(), FB.end(), my_mutable_functor);
std::cout << FB << std::endl; // As expected: 'FrAnck BArbier'

from = 'b';
to = 'B'; // Pay attention: capture does not mean argument passing!
std::for_each(FB.begin(), FB.end(), my_mutable_functor);
std::cout << FB << std::endl; // No effect: 'FrAnck BArbier'
See also

Initializer

Rule(s)
Example (with initializer) Smart_pointers.Cpp.zip 
'.h' file:
class Mammoth : public Elephantidae {
private:
    const Mammoth* _best_friend = nullptr;
public: // 'inline' is for compactness only!
    const std::string name;
    inline Mammoth(const std::string& name = "") : name(name) {};
    inline void best_friend(const Mammoth* best_friend) {_best_friend = best_friend;};
};

'.cpp' file:
std::unique_ptr<Mammoth> the_very_first_Mammoth(new Mammoth("the_very_first_Mammoth"));
// Compilation error (capture by copy cannot apply on movable-only objects as 'std::unique_ptr' objects):
//    auto my_lambda_expression = [the_very_first_Mammoth] (std::unique_ptr<Mammoth>&& m) {
//        m->best_friend(the_very_first_Mammoth.get());
//    };
// Capture with initializer (C++14):
auto my_lambda_expression = [best_friend = the_very_first_Mammoth.get()] (std::unique_ptr<Mammoth>&& m) {
    m->best_friend(best_friend);
};
my_lambda_expression(std::move(m0)); // 'the_very_first_Mammoth' becomes best friend of 'm0'...
assert(m0.get() != nullptr); // Forced 'move' does not empty 'm0'...

Lambda expression and STL

Rule(s)
Example (get the values of a map) Smart_pointers.Cpp.zip 
std::unordered_map<std::string, std::unique_ptr<Mammoth>&& > zoo; // Indexed access based on names...
std::unique_ptr<Mammoth> m = std::make_unique<Mammoth>("m");
zoo.emplace(m.get()->name, std::move(m)); // 'zoo.try_emplace(m.get()->name, std::move(m));' // C++17
assert(m.get() != nullptr); // Forced 'move' does not empty 'm'...

std::vector<std::unique_ptr<Mammoth> > values; // Arrrrrgggggllll: no 'values' function on maps!
std::transform(std::begin(zoo), std::end(zoo), std::back_inserter(values),
    [](/* auto */ /* -> from C++14 */ const decltype(zoo)::value_type& pair) {
        static_assert(std::is_same_v<decltype(pair.second), std::unique_ptr<Mammoth>&&>, "Type checking failed, why?");
        return std::move(pair.second); // This empties the original map of resources!
    });
assert(m.get() == nullptr); // Forced 'move' emptied 'm'...
Example (get the values of a map, cont'd) Smart_pointers.Cpp.zip 
std::vector<const Mammoth*> values;
std::transform(std::begin(zoo), std::end(zoo), std::back_inserter(values),
    [](const auto& pair) {
        return pair.second.get();
    });
assert(m.get() != nullptr);
Example (constructibility and copyability) Lambda_expression_.Cpp.zip 
'.h' file:
class Election {
    std::string _separator;
    std::unordered_multimap<std::string, std::string> _situation;
public:
    static const std::string Candidate;
    static const std::string Challenger;
    static const std::string President;
    static const std::string Prime_minister;
    Election(const std::string&, const std::initializer_list<std::unordered_multimap<std::string, std::string>::value_type>&);
    std::string candidates() const;
    void change_separator(const std::string&);
};

'.cpp' file:
std::string Election::candidates() const {
    std::string result;

    auto is_candidate_predicate = [](const std::unordered_multimap<std::string, std::string >::value_type& someone_in_role) -> bool {
        // As shown, static members, e.g., 'Election::Candidate', do not require capture:
        return Election::Candidate.compare(someone_in_role.second) == 0;
    };

    decltype(is_candidate_predicate) is_candidate_predicate_; // Ok Visual Studio C++20 while "niet" for C++14-17
    std::cout << "'std::is_trivially_constructible_v<decltype(is_candidate_predicate)>': " <<
    std::is_trivially_constructible_v<decltype(is_candidate_predicate)> << std::endl;

    decltype(is_candidate_predicate) copy_of_is_candidate_predicate = is_candidate_predicate;
    std::cout << "'std::is_trivially_copyable_v<decltype(is_candidate_predicate)>': " <<
    std::is_trivially_copyable_v<decltype(is_candidate_predicate)> << std::endl; 'true'

    copy_of_is_candidate_predicate = is_candidate_predicate; // Ok Visual Studio C++20 while "niet" for C++14-17
    std::cout << "'std::is_trivially_assignable_v<decltype(is_candidate_predicate), decltype(is_candidate_predicate)>': " <<
    std::is_trivially_assignable_v<decltype(is_candidate_predicate), decltype(is_candidate_predicate)> << std::endl;
    …
}
Example (predicate, unary and binary operations) Lambda_expression_.Cpp.zip 
std::string Election::candidates() const {
    …
    if (std::none_of(std::begin(_situation), std::end(_situation), is_candidate_predicate))
        result += "Nobody is " + Election::Candidate;
    else {
        std::unordered_multimap< std::string, std::string > candidates;
        std::copy_if(/*std::execution::par,*/ _situation.begin(), _situation.end(), std::inserter(candidates, candidates.end()),
            [](auto& someone_in_role) {
                return Election::Candidate.compare(someone_in_role.second) == 0;
            });

        std::vector<std::string > keys;
        std::transform(std::begin(candidates), std::end(candidates), std::back_inserter(keys),
            [](decltype(candidates)::value_type& pair) {
                return pair.first;
        });

	// result = Election::Candidate + ": " + std::reduce(/*std::execution::par,*/ keys.begin(), keys.end(), result,
	//  [this](const std::string& k1, const std::string& k2) {
	//      // Compilation error comes from 'candidates' is a 'const' member function...:
	//      this->change_separator(" # "); // 'change_separator' is a non-'const' member function...
	//          return k1 + this->_separator + k2; // Note that '[=]' is enough to capture 'this->_separator'
	//      });

        result = Election::Candidate + ": " + std::reduce(/*std::execution::par,*/ keys.begin(), keys.end(), result,
            // Initializer (C++14) and '*this' (C++17):
            [my_this = *this](const std::string& k1, const std::string& k2) mutable {
                my_this.change_separator(" # "); // 'change_separator' is a non-'const' member function...
                    return k1 + my_this._separator + k2;
            });
        }
    return result;
}

Generic lambda expression (C++14)

Rule(s)
Example (principle) Lambda_expression_.Cpp.zip 
class { // Closure type
public:
    template<typename X> void operator()(X& x) const {x++;}
} increment;
…
int x = 0;
// More simply, '::increment(x);'
::increment.operator()/*<int>*/(x); // Instantiation of template member function in closure type
std::cout << "::increment(x): " << x << std::endl; // '1'
auto increment = [](auto& x) { // Generic lambda...
    x++;
};
increment(x); // Instantiation of generic lambda...
std::cout << "increment(x): " << x << std::endl; // '2'
Example (instantiation from iterator type) Lambda_expression_.Cpp.zip 
std::unordered_multimap<std::string, std::string > situation_of_French_2012_presidential_election {
    {"Macron", "President"}, {"Macron", "Candidate"},
    {"Philippe", "Prime minister"},
    {"Mélanchon", "Challenger"}, {"Mélanchon", "Candidate"},
    {"Le Pen", "Challenger"}, {"Le Pen", "Candidate"}
};
std::unordered_multimap<std::string, std::string >::iterator iterator = situation_of_French_2012_presidential_election.begin();
increment(iterator); // Instantiation of generic lambda...
std::cout << "increment(iterator): " << (*iterator).second << std::endl; // No order, so... value of any element

From generic to polymorphic lambda expression

Rule(s)
Example (principle) Inheritance_genericity_gcc.Cpp.zip 
'.h' file:
class Cabbage : public Vegetable {
public:
    bool operator==(const Cabbage&) const;
    bool operator!=(const Cabbage&) const;
};

class Carrot : public Vegetable {
public:
    bool operator==(const Carrot&) const;
    bool operator!=(const Carrot&) const;
    Vegetable_colors color() const;
};

'.cpp' file:
bool Cabbage::operator==(const Cabbage& cabbage) const {
    return std::is_same<decltype(*this), decltype(cabbage)>::value; // For simplification
}
bool Cabbage::operator!=(const Cabbage& cabbage) const {
    return !this->operator==(cabbage);
}
bool Carrot::operator==(const Carrot& carot) const {
    return std::is_same<decltype(*this), decltype(carot)>::value; // For simplification
}
bool Carrot::operator!=(const Carrot& carot) const {
    return !this->operator==(carot);
}
bool operator==(const Carrot& carot, const Cabbage& cabbage) {
    return true; // "Mélanger des choux et des carottes !"
}
bool operator==(const Cabbage& cabbage, const Carrot& carot) {
    return false; // "Mélanger des carottes et des choux !"
}
…
// Generic and polymorphic lambda (C++14) -> https://stackoverflow.com/questions/26435052/using-template-parameter-in-a-generic-lambda
// Visual Studio 2020 is not able to deal with 'decltype(a)':
auto equals_generic = [](auto a, decltype(a) b) {
    return a == b;
};
auto equals_polymorphic = [](auto a, auto b) {
    return a == b;
};

std::cout << std::boolalpha << equals_generic(Cabbage{}, Cabbage{}) << std::endl;
std::cout << std::boolalpha << equals_generic(Carrot{}, Carrot{}) << std::endl;
// std::cout << std::boolalpha << equals_generic(Cabbage{}, Carrot{}) << std::endl; // Compilation error due to non-polymorphic:
// std::cout << std::boolalpha << equals_generic(Carrot{}, Cabbage{}) << std::endl; // Compilation error due to non-polymorphic:

std::cout << std::boolalpha << equals_polymorphic(Carrot{}, Carrot{}) << std::endl;
std::cout << std::boolalpha << equals_polymorphic(Cabbage{}, Cabbage{}) << std::endl;
std::cout << std::boolalpha << equals_polymorphic(Cabbage{}, Carrot{}) << std::endl;
std::cout << std::boolalpha << equals_polymorphic(Carrot{}, Cabbage{}) << std::endl;
See also
From C++11, pointers benefit from being managed from the nullptr keyword of std::nullptr_t type. The other key improvement is the (definitive) support for smart pointer.

nullptr keyword

Rule(s)
Example NULL_PTR.Cpp.zip 
int i = 0;
i++;
int* my_pointer_on_an_int_variable = &i; // Memory address of 'i'
std::cout << *my_pointer_on_an_int_variable << '\n'; // '1' is displayed...
int& j = i;
std::cout << j << '\n'; // '1' is displayed...
my_pointer_on_an_int_variable = NULL; // '#include <cstddef>' may be omitted to access 'NULL'
std::cout << *my_pointer_on_an_int_variable << '\n'; // Ooops!
Example NULL_PTR.Cpp.zip 
template<typename F, typename P> void gf(F f, P p) { // 'gf' generic function
    f(p); // Call of 'f' with 'p' as parameter...
}

void g(void* pointer) {
    std::cout << "'g' function is called...\n"; // '#include <iostream>'
}

int main(/* int argc, char** argv */) {
    g(NULL); // Fine
    g(0); // This works because 'NULL == 0' from C, but not so fine...

    gf(g, nullptr); // Fine
    //    gf(g, NULL); // Error comes from type checking: type of 'NULL' is not 'void*' 

    return 0;
}
See also

Redefining new and delete

Example Smart_pointers.Cpp.zip 
// '.h' file:
class Elephant : public Elephantidae {
    static void* _Preallocated_memory;
    …
public:
    void* operator new(size_t) noexcept(false);
    void operator delete(void*) noexcept(true);
    …
};

// '.cpp' file(s):
void* Elephant::_Preallocated_memory = nullptr;

void* Elephant::operator new(size_t size) noexcept(false){
    if (_Preallocated_memory) return _Preallocated_memory;
    void* p = std::malloc(size);
    // Alternative (caution: if 'new' is *inherited* then the allocated size is wrong):
    // void* p = ::new Elephant(); // Call of global 'new' to avoid recursion...
    // Solutions: (1) use 'final' for blocking inheritance from 'Elephant', or (2) use
    // private inheritance, i.e., 'class African_elephant : private Elephant',
    // which prevents undesired 'new' inheritance: 'African_elephant* ae = new African_elephant;' -> compilation error
    if (!p) throw std::bad_alloc(); // <=> 'p == nullptr' and 'ptr == NULL'
    return p;
}

void Elephant::operator delete(void* p) noexcept(true) {
    if (_Preallocated_memory) std::free(_Preallocated_memory);
    // Alternative:
    // if (_Preallocated_memory) ::delete _Preallocated_memory; // Call of global 'delete' to avoid recursion...
    _Preallocated_memory = p; // Recycle...
}
…
Elephant* Babar = new Elephant;
delete Babar;
Elephant* Elmer = new Elephant;
delete Elmer;
assert(Babar == Elmer);
// Before terminating, please release pool, if any, pointed by 'Elephant::_Preallocated_memory'

Smart pointers

Rule(s)
Example (principle) Smart_pointers.Cpp.zip 
// Modern C++ allows the allocation of pointers *without* the need of user-defined deletions:
std::unique_ptr<Mammoth> m0(new Mammoth("m0")); // '#include <memory>'
// std::unique_ptr<Mammoth> bug(m0.get()); // Hell and damnation! This may work only if 'm0.release();' occurs before resource destruction...
std::unique_ptr<Mammoth> m1 = std::make_unique<Mammoth>("m1"); 
// std::unique_ptr<Mammoth> m2 = m1; // Compilation error...
Mammoth m = *m1; // '*' operator overridden within 'std::unique_ptr'
Mammoth* pm = m1.get(); // Get the managed object, caution: double pointing!
assert(pm != nullptr);
pm = m1.release();
assert(m1.get() == nullptr); // Single pointing, i.e., 'pm'
Example (sharing) Smart_pointers.Cpp.zip 
std::shared_ptr<Mammoth> ma;
{
    std::shared_ptr<Mammoth> mb = std::make_shared<Mammoth>();
    ma = mb; // In essence, no compilation error...
    assert(ma.use_count() == 2);
} // No delete on 'mb' since shared with 'ma'
assert(ma.use_count() == 1);
Example (casting) Smart_pointers.Cpp.zip 
// '.h' file:
class Elephantidae { // 'Elephant' and 'Mammoth' as subtypes...
private:
    std::list<std::shared_ptr<Elephantidae> > _family_members;
protected:
    virtual ~Elephantidae() = default; // This makes 'Elephantidae' polymorphic to be used with 'dynamic_cast' *AND* 'dynamic_pointer_cast'
public:
    void push_family_member(const std::shared_ptr<Elephantidae>&);
    std::shared_ptr<Elephantidae> peek_family_member() const;
};

// '.cpp' file(s):
std::shared_ptr<Elephantidae> Jumbo = std::make_shared<Elephant>();
// 'Jumbo' is passed by reference (note that passing by copy would increment the number of pointers returned by 'use_count'):
ma->push_family_member(Jumbo); // Overridden '->' operator in 'std::shared_ptr'
// std::shared_ptr<Elephant> pe = ma->peek_family_member(); // Compilation error...
std::shared_ptr<Elephant> pe = std::dynamic_pointer_cast<Elephant>(ma->peek_family_member());
assert(pe);
Example (weak sharing) Smart_pointers.Cpp.zip 
std::weak_ptr<Mammoth> mx; // Weak pointer aims at replacing "raw" pointer obtained by 'get'...
{
    std::shared_ptr<Mammoth> my = std::make_shared<Mammoth>();
    mx = my;
    assert(my.use_count() == 1); // Weak pointer has no impact on the number of pointers returned by 'use_count'
    std::shared_ptr<Mammoth> mz = mx.lock(); // 'lock' copies into 'shared_ptr' object before usage...
    std::cout << mz.get() << std::endl;
} // Delete on 'my'
assert(mx.use_count() == 0);
Example (resource-based management) Smart_pointers.Cpp.zip 
std::unique_ptr<Mammoth> La_Madeleine(new Mammoth("Le mammouth gravé sur ivoire de La Madeleine (Tursac, Dordogne)"));
std::unique_ptr<Mammoth>&& La_Madeleine_is_moved = std::move(La_Madeleine);
assert(La_Madeleine.get() != nullptr && La_Madeleine.get() == La_Madeleine_is_moved.get());
La_Madeleine.release();
assert(La_Madeleine.get() == nullptr && La_Madeleine_is_moved.get() == nullptr);

std::unique_ptr<Mammoth> La_Grande_Liakhov(new Mammoth("La Grande Liakhov, l'île aux mammouths"));
Mammoth* La_Grande_Liakhov_resource = La_Grande_Liakhov.get();
std::unique_ptr<Mammoth> La_Grande_Liakhov_is_moved = std::move(La_Grande_Liakhov);
assert(La_Grande_Liakhov.get() == nullptr && La_Grande_Liakhov_resource == La_Grande_Liakhov_is_moved.get());
Traits in C++11 are the possibility of getting metadata on “effective” types while writing trait logic on anonymous types (genericity). The list of available traits reflects the way C++ moves from C++11 to C++20 including “recent” obsolescenses.

Meta-programming

Rule(s)
Example Palindrome.Cpp.zip 
// 'constexpr' works with 'static' only...
// 'constexpr' allows compile-time initialization:
constexpr static const std::pair<char, char> _Intervals[] = {std::pair<char, char>('a', 'z'), std::pair<char, char>('A', 'Z')};
constexpr static const int _Intervals_size = 2; // No need with C++17: 'std::size(_Intervals)'
Example Constexpr.Cpp.zip 
template<int... Integers> // C++14
constexpr std::array<int, sizeof...(Integers)> create_array(std::integer_sequence<int, Integers...>) noexcept {
	return std::array<int, sizeof...(Integers)> { Integers... }; // Aggregate initialization...
}
constexpr std::array<int, 20> My_array = ::create_array(std::make_integer_sequence<int, 20>{});
static_assert(My_array[19] == 19);
Rule(s)
Example Constexpr.Cpp.zip 
class Constexpr_example {
public:
    constexpr static int N = 8;
};

template<int N> constexpr bool Is_prime() noexcept {
	if constexpr (N < 2) return false; // C++17
	if constexpr (N == 2) return true; // C++17
	else { // This branch is discarded at compilation time when 'N == 2'
		bool is_prime = true;
		for (int i = 2; i < N; i++)
			if (N % i == 0) {
				is_prime = false;
				break;
			}
		return is_prime;
	}
}

static_assert(::Is_prime<2>()); // No compilation error
// static_assert(::Is_prime<Constexpr_example::N>()); // Compilation error since 'Constexpr_example::N == 8'
Rule(s)
Example (naive approach) Constexpr_.Cpp.zip 
constexpr int N = 10; // Must be initialized
constexpr int Native_array[N] = {}; // Must be initialized

constexpr int Primes_() {
    int cursor = 0;
    for (int i = 2; cursor != N; i++) { // Candidate prime numbers...
        // Naive solution:
        bool is_prime = true;
        for (int j = 2; j < i; j++)
            if (i % j == 0) {
                is_prime = false;
                break;
            }
        //        if (is_prime)
        //            // Compilation error: assignment of read-only location:
        //            Native_array[cursor++] = i;
    }
	return 0; // Done...
}

 int Return = Primes_(); // This code causes the compiler to crash in a random way!
 // static_assert(::Native_array[0] == 2); // It fails!

constexpr std::array<int, N> Primes() {
    std::array<int, N> primes = {}; // Must be initialized
    int cursor = 0;
    for (int i = 2; cursor != N; i++) { // Candidate prime numbers...
        // Naive solution:
        bool is_prime = true;
        for (int j = 2; j < i; j++)
            if (i % j == 0) {
                is_prime = false;
                break;
            }
        //        if (is_prime)
        //            // Compilation error: call to non-'constexpr' function:
        //            primes[cursor++] = i;
        return primes;
    }
}

class Constexpr_example {
public:
    constexpr static std::array<int, N> Primes = ::Primes();
};
Example (compilation-time code only!) Constexpr.Cpp.zip 
constexpr int Not_prime = -1;

constexpr int As_prime(int n) {
	if (n < 2) return ::Not_prime;
	for (int i = 2; i < n; i++)
		if (n % i == 0)
			return ::Not_prime;
	return n;
}

// 'std::index_sequence' and 'std::make_index_sequence' are specializations of
// 'std::integer_sequence' and 'std::make_integer_sequence' with 'T' = 'std::size_t'
/** Internal '_create_array' template function called by 'create_array' */
template<typename Function, std::size_t... Integers>
// Trailing return type thanks to 'auto':
constexpr/*[]*/ auto _create_array(Function f, std::index_sequence<Integers...>) ->
// Returned type:
std::array<std::invoke_result_t<Function, std::size_t>, sizeof...(Integers)> {
	return { { f(Integers)... } }; // Aggregate initialization
}

template<int N, typename Function>
// Trailing return type based on 'auto':
constexpr/*[]*/ auto create_array(Function f) ->
// Returned type:
std::array<typename std::result_of<Function(std::size_t)>::type, N> {
	// 'std::make_index_sequence<7>{}' -> '<0,1,2,3,4,5,6,7>' become 'Integers'
	return _create_array<Function>(f, std::make_index_sequence<N>{});
}

constexpr std::array<int, Constexpr_example::N> Primes =
	::create_array<Constexpr_example::N/*, decltype(&::As_prime)*/>(::As_prime);
static_assert(Primes[0] == ::Not_prime); // No compilation error
static_assert(Primes[1] == ::Not_prime); // No compilation error
static_assert(Primes[2] != ::Not_prime); // No compilation error
static_assert(Primes[3] != ::Not_prime); // No compilation error
Rule(s)
Example Constexpr.Cpp.zip 
int main() {
    …
    /** Code is put inside 'main' for illustration purpose only! */
    // 'N' is made available in local scope ('main') for *CAPTURE*;
    constexpr int N = Constexpr_example::N;
    // 'constexpr' lambda expression:
    constexpr auto my_lambda = [N /* Capture 'constexpr' only */]() {
        if (::Is_prime<Constexpr_example::N>()) // '::Is_prime<N>()' *DOES NOT* work...
            return ::As_prime(N); // '::As_prime(Constexpr_example::N)' *DOES* work...
        return ::Not_prime;
    };
    static_assert(my_lambda() == ::Not_prime); // No compilation error since 'Constexpr_example::N == 8'
}
See also

Basic traits: std::is_class, std::is_same

Rule(s)
Example (std::is_same)
std::cout << std::boolalpha << std::is_same<std::pair<const std::string, std::string>,
std::unordered_map<std::string, std::string >::value_type >::value << std::endl; // 'true'
Example
'.h' file:
class ClassWith_toString {
    public:
        std::string toString() {return "Returned by 'toString'...";}
    …
};
class ClassWithout_toString final {};

'.cpp' file:
std::cout << std::boolalpha;
std::cout << std::is_class<ClassWith_toString>::value << std::endl; // 'true'
std::cout << std::is_trivially_copyable<ClassWith_toString>::value << std::endl; // 'true'
std::cout << std::is_final<ClassWith_toString>::value << std::endl; // 'false'
std::cout << std::is_final<ClassWithout_toString>::value << std::endl; // 'true'
Resource(s)

Reinforcing type checking

Rule(s)
Example Meta_programming.Cpp.zip 
// '.h' file:
#include <type_traits>
class Note {
    virtual void initialization();
};
class Confidential_note : public Note {
    void initialization() override;
};

template <typename T> // 'my_function' has to work with a polymorphic type...
// Return type is 'void' due to 'std::enable_if_t' inference succeeds:
typename std::enable_if_t<std::is_polymorphic_v<T> > my_function(T&&); // C++17 required

// '.cpp' file:
int main() {
    ::my_function(Note());
    ::my_function(Confidential_note());
    // ::my_function("'std::string' is not a polymorphic type..."); // Compilation error...
}

Code adaptation

Rule(s)
Example Inheritance_genericity_gcc.Cpp.zip 
template<typename Any> class Pointer_based_hash {
public:
    // If 'std::is_pointer<Any>::value' is true then 'std::enable_if' has a public member 'typedef' type, which equals 'Return_type' else there is no member 'typedef' 
    template<typename Return_type = std::size_t> typename std::enable_if<std::is_pointer<Any>::value, Return_type>::type
    operator()(const Any pointer) const {
        std::hash < std::bitset<sizeof (Any)> > hash;
        return hash(reinterpret_cast<uintptr_t> (pointer)); // Storage relies on memory address!
    }
    template<typename Return_type = std::size_t> typename std::enable_if<!std::is_pointer<Any>::value, Return_type>::type
    operator()(const Any& any) const {
        std::hash < std::bitset<sizeof (Any*)> > hash;
        return hash(reinterpret_cast<uintptr_t> (&any)); // Storage relies on memory address!
    }
};

template <typename T> class Garden {
private:
    // 'Pointer_based_hash<T>' (as second anonymous type) acts as a functor (definition of 'operator()' required in 'Pointer_based_hash<T>'):
    std::unordered_set <T, Pointer_based_hash<T> > _garden;
public:
    Garden(const T&);
};

Substitution Failure Is Not An Error (SFINAE)

Rule(s)
Example (simple) Meta_programming.Cpp.zip 
// '.h' file:
#include <type_traits>class A {
public:
    // virtual ~A(); // 'A' *IS NOT* polymorphic!
    using Internal_type = A; // For simplification, but stupid...
};

template <typename T> // 'my_function' has to work with a polymorphic type...
// Return type is 'void' due to 'std::enable_if_t' inference succeeds:
typename std::enable_if_t<std::is_polymorphic_v<T> > my_function(T&&) { std::cout << "Base ver." << std::endl; }; // C++17 required
// Specialization of 'my_function':
template <typename T> void my_function(typename T::Internal_type&&) { std::cout << "Specialization, SFINAE" << std::endl; };

// '.cpp' file:
int main() {
    ::my_function<A>(A()); // 'Specialization, SFINAE'
}
Example (complex) SFINAE.Cpp.zip 
// '.h' file:
template <typename T> class Has_toString { // Inspiration: https ://gist.github.com/fenbf/d2cd670704b82e2ce7fd
private:
	typedef wchar_t No; // 'sizeof(wchar_t) == 2'
	static_assert(sizeof(No) == 2, "'sizeof(No) != 2', impossible!");
	typedef char Yes; // 'sizeof(char) == 1'
	static_assert(sizeof(Yes) == 1, "'sizeof(Yes) != 1', impossible!");
	// Two following functions have *NO BODY* since they only play a role at *compile time* (uncomment for test)
	// Versions are instantiated by the compiler according to *effective type* injected in 'Has_toString':
	template <typename ...> static No _Test(...) /*{ std::string s = "Never executed..."; }*/;
	/* '_Test(...)' is inferred matches to all parameters. It is then inferred when 'Yes _Test(decltype(&C::toString))' *IS NOT*
	*/
	template <typename C> static Yes _Test(decltype(&C::toString)); // Get the (returned) type of the 'toString' function via member function pointer!
	/* '_Test(decltype(&C::toString))' is inferred since 'std::declval<std::nullptr_t>())' conforms to 'decltype(&C::toString)'
	*/
public:
	static std::string Get_metadata() {
		std::string result = "decltype(std::declval<Yes>()): " + std::string(typeid(decltype(std::declval<Yes>())).name()) + '\n'
			+ "decltype(_Test<T>(nullptr)): " + std::string(typeid(decltype(_Test<T>(nullptr))).name());
		return result;
	};
	// 'T' plays the role of 'C' in 'Test', i.e., 'std::string' plays the role of 'T' in 'std::enable_if<Has_toString<T>::Result, std::string>'
	static constexpr const bool Result = sizeof(_Test<T>(std::declval<std::nullptr_t>())) == sizeof(Yes);
	// Simplified alternative ('nullptr' matches to the member function pointer '&C::toString'):
	static constexpr const bool Result_ = std::is_same<decltype(_Test<T>(nullptr)), 
		// 'std::declval<Yes>()' returns a *rvalue ref.* whose type is 'Yes':
		std::remove_reference_t<decltype(std::declval<Yes>())> >::value; // Remove '&&'
};

template<typename T>
// 'Has_toString<T>::Result' exprime une condition calculée "à la compilation"
// La fonction 'Call_toString' *n'est pas instanciable* du point de vue de la généricité si 'false' :
/* C++14: */ typename std::enable_if_t<Has_toString<T>::Result, std::string> // <=> 'std::enable_if<Has_toString<T>::Result, std::string>::type' in C++11
Call_toString(T* t) {
    /* 'T' has 'toString' ... */
    return t->toString();
}
std::string Call_toString(...) { // Version disponible (*non instanciée*) pour traiter 'false'
	return "'toString()' method is undefined...";
}

// '.cpp' file:
class ClassWith_toString {
    public:
        std::string toString() {return "Returned by 'toString'...";}
        …
};

class ClassWithout_toString final {};
…
std::cout << std::boolalpha << "Has_toString<ClassWith_toString>: " << Has_toString<ClassWith_toString>::Result_ << std::endl; // 'true'
std::cout << std::boolalpha << "Has_toString<ClassWithout_toString>: " << Has_toString<ClassWithout_toString>::Result << std::endl; // 'false'
std::cout << std::boolalpha << "Has_toString<int>: " << Has_toString<int>::Result << std::endl; // 'false'

“My effective type is itself a template!”

Rule(s)
Example Trait.Cpp.zip 
// '.h' file:
template<typename T> class My_template { /* Given a template class...*/ };

namespace V1 {
    template<typename Realized, template<typename> class Realizer> class is_realization_of : public std::integral_constant<bool, false > /* <=> std::false_type */ {};
    template<typename Realized, template<typename> class Realizer> class is_realization_of<Realizer<Realized>, Realizer> : public std::true_type {};
    // 'My_template_realization' is indeed 'My_template<T>' for some 'T':
    template<typename My_template_realization> class My_class {
        // Caution: comma is misinterpreted by the pre-processor, requiring extra parentheses:
        static_assert((is_realization_of<My_template_realization, My_template>::value), "failure");
    };
}

namespace V2 { // For any number of (template) effective types...
    template<template<typename...> class TT, typename T> class is_realizer_of : std::false_type {};
    template<template<typename...> class TT, typename... Ts> class is_realizer_of<TT, TT<Ts...> > : std::true_type {};
    template<typename My_template_realization> class My_class {
        static_assert((is_realizer_of<My_template, My_template_realization>::value), "failure");
    };
}

// '.cpp' file:
// V1::My_class<int> mc1; // 'static_assert' error since 'int' is not a template class!
V1::My_class<My_template<int> > mc2; // OK!
See also
Multithreading in C++11 (#include <thread>) is the introduction of a self-contained rationale API for parallel (even, concurrent) programming beyond heavy processes in an operating system (OS). Threads of control are in essence light processes that cross operating systems' boundaries and thus overcome incompatibilities (between UNIX and Windows especially).

Effective concurrency

Rule(s)
Example Illustration_of_thread_local.Cpp.zip 
std::cout << "Concurrent supported threads: " << std::thread::hardware_concurrency() << '\n';

Thread state

Rule(s)
Example Illustration_of_thread_local.Cpp.zip 
bool stop = false;
// Capture 'stop' by reference for guaranteed stopping:
std::thread my_thread([&stop]() -> void { // Thread creation from lambda expression...
    while (!stop) { ... }
    std::cout << "Just ends..." << '\n';
});
assert(my_thread.joinable());
my_thread.detach();
assert(!my_thread.joinable());
std::this_thread::sleep_for(std::chrono::seconds(1));
stop = true;
try {
    my_thread.join();
} catch (std::system_error& se) { // Inheritance graph: 'std::exception' < 'std::runtime_error' < 'std::system_error' (C++11)
    std::cerr << se.what() << '\n'; // "thread::join failed: Invalid argument" (g++ message)
}

thread_local keyword

Rule(s)
Example Illustration_of_thread_local.Cpp.zip 
// '.h' file:
class Illustration_of_thread_local {
    /** The game is, as much as possible, avoiding the following inconsistent compositions:
     * "FrançoisSarkozy" and "NicolasHollande" */
    // Threads using '_Francois' have their own copy (read-only mode):
    static thread_local const std::string _Francois;
    static thread_local const std::string _Hollande;
    static thread_local const std::string _Nicolas;
    static thread_local const std::string _Sarkozy;
    static std::string _Patronym;

    static bool _Checkable;
    static bool _Stop;

    static std::mutex _Mutex; // Create critical section for string manipulation ('#include <mutex>')...

    static void _Check();
    static void _Set(std::string const&, std::string const&);
    static void _Set_Francois_Hollande();
    static void _Set_Nicolas_Sarkozy();
public:
    static int Bads;
    static int Goods;
    static void Go();
};

// '.cpp' file:
thread_local const std::string Illustration_of_thread_local::_Francois = "François";
thread_local const std::string Illustration_of_thread_local::_Hollande = "Hollande";
thread_local const std::string Illustration_of_thread_local::_Nicolas = "Nicolas";
thread_local const std::string Illustration_of_thread_local::_Sarkozy = "Sarkozy";

std::string Illustration_of_thread_local::_Patronym = "?";
bool Illustration_of_thread_local::_Checkable = false;
bool Illustration_of_thread_local::_Stop = false;

int Illustration_of_thread_local::Bads = 0;
int Illustration_of_thread_local::Goods = 0;

std::mutex Illustration_of_thread_local::_Mutex;

void Illustration_of_thread_local::_Check() {
    while (!_Stop) {
        if (_Checkable) {
            // 'thread_local' for '_Francois', '_Hollande', '_Nicolas' and '_Sarkozy':
            if (_Patronym.compare(_Francois + _Sarkozy) == 0 || _Patronym.compare(_Nicolas + _Hollande) == 0)
                Bads++;
            else
                Goods++;
            _Checkable = false;
        }
    }
}

void Illustration_of_thread_local::_Set(std::string const& given_name, std::string const& surname) {
    /* Processing is *deliberately* slowed down through two statements instead of '_Patronym = given_name + surname;' */
    // const std::lock_guard<std::mutex> critical_section(_Mutex); // Lightweight...
    std::unique_lock<std::mutex> critical_section(_Mutex); // Heavyweight...
    //    critical_section.try_lock(); // Execution error since constructor does it just before...
    _Patronym = given_name; // Random segmentation fault if no critical section set up...
    critical_section.unlock();
    critical_section.lock();
    _Patronym += surname; // Random segmentation fault if no critical section set up...
    critical_section.unlock();
} // Unlocking 'std::lock_guard' occurs at destruction time...

void Illustration_of_thread_local::_Set_Francois_Hollande() {
    while (!_Stop) {
        _Set(_Francois, _Hollande); // 'thread_local' for '_Francois', '_Hollande'...
        _Checkable = true;
    }
}

void Illustration_of_thread_local::_Set_Nicolas_Sarkozy() {
    while (!_Stop) {
        _Set(_Nicolas, _Sarkozy); // 'thread_local' for '_Nicolas' and '_Sarkozy'...
        _Checkable = true;
    }
}

void Illustration_of_thread_local::Go() {
    std::cout << "Concurrent supported threads: " << std::thread::hardware_concurrency() << '\n';

    std::thread Check(&Illustration_of_thread_local::_Check);
    std::thread Set_Francois_Hollande(&Illustration_of_thread_local::_Set_Francois_Hollande);
    std::thread Set_Nicolas_Sarkozy(&Illustration_of_thread_local::_Set_Nicolas_Sarkozy);

    std::this_thread::sleep_for(std::chrono::milliseconds(10));
    _Stop = true;

    Check.join();
    Set_Francois_Hollande.join();
    Set_Nicolas_Sarkozy.join();
}
See also

Condition variable

Rule(s)
Example Short_dead_lock.Cpp.zip 
// '.h' file:
#include <condition_variable>
#include <mutex>

class Short_dead_lock {
private:
    bool __stop = false;
    std::condition_variable _my_condition_variable;
    std::mutex _my_mutex;
public:
    void f();
private:
    void _g();
    inline bool _stop() const {return __stop;}; // 'inline' is for pedagogical reasons *ONLY* (compactness of code)
};

// '.cpp' file:
void Short_dead_lock::f() {
    std::cout << "Start of 'f()' in thread: " << std::this_thread::get_id() << std::endl;
    // _g(); // '_g' *MUST* be started in another thread to avoid self-deadlock: 
    std::thread g(&Short_dead_lock::_g, this); // This starts 'g'...
    std::this_thread::sleep_for(std::chrono::milliseconds(5000)); // Wait 5s...
    // __stop = true; // Required for ver. 2
    // Release '_g':
    _my_condition_variable.notify_all(); // Required for ver. 1 and ver. 2...
    g.join(); // Wait for 'g' thread to complete...
    std::cout << "End of 'f()'" << std::endl;
}

void Short_dead_lock::_g() {
    std::cout << "Start of '_g()' in thread: " << std::this_thread::get_id() << std::endl;
    std::unique_lock<std::mutex> lock(_my_mutex);
    // Ver. 1:
    _my_condition_variable.wait(lock);
    // Ver. 2:
    // _my_condition_variable.wait(lock, std::bind(&Short_dead_lock::_stop, this)); // 'std::bind' <=> 'bind' in JavaScript
    std::cout << "End of '_g()'" << std::endl;
}

int main(int argc, char** argv) {
    Short_dead_lock sdl;
    sdl.f();

    return 0;
}

Atomicity

Rule(s)
Example Atomic.Cpp.zip 
std::array<int, 5> my_array{ 1, 4, 3, 2, 5 };
std::atomic< std::array<int, 5>* > my_atomic{ &my_array };

std::thread ascending(
    [&my_atomic]() {
        // Resource is unavailable:
        std::array<int, 5>* my_array = nullptr;
        // Race condition, try to be the first to get the resource:
        do { my_array = my_atomic.exchange(nullptr); } while (my_array == nullptr);
        std::sort(my_array->begin(), my_array->end(),
            [](const int a, const int b) {
                // std::cout << "\tascending a: " << a << " b: " << b << std::endl;
                return a > b;
            });
        // Release resource:
        my_atomic.exchange(my_array);
});

std::thread descending(
    [&my_atomic]() {
	// Resource is unavailable:
	std::array<int, 5>* my_array = nullptr;
	// Race condition, try to be the first to get the resource:
	do { my_array = my_atomic.exchange(nullptr); } while (my_array == nullptr);
	std::sort(my_array->begin(), my_array->end(),
            [](const int a, const int b) {
                // std::cout << "\tdescending a: " << a << " b: " << b << std::endl;
                return a < b;
            });
        // Release resource:
        my_atomic.exchange(my_array);
});

descending.join();
ascending.join();

for (const int i : my_array) // Either ascending or descending based on the "loser thread"
    std::cout << "\t" << i;

Towards asynchronous programming

Rule(s)
Example Promise.Cpp.zip 
// '.h' file:
class Image {
    static std::list<std::launch> _Start; // Benchmarking only...
    static std::list<std::launch> _End; // Benchmarking only...
    static std::mutex _Mutex; // Benchmarking only...

    const std::string _file_name;
public:
    Image(std::string&&);
    std::string process(const std::launch&) noexcept(false);
};
// '.cpp' file:
std::string Image::process(const std::launch& launch) noexcept(false) {
    
    std::string start = launch == std::launch::deferred ? "Deferred" :
        launch == (std::launch::async | std::launch::deferred) ? "Default" :
        launch == std::launch::async ? "Async" : "?";
    start += " (start)";
    {
        const std::lock_guard<std::mutex> critical_section(_Mutex);
        _Start.push_back(launch);
        for (std::launch launch : _Start) {
            start += " < ";
            start += launch == std::launch::deferred ? "Deferred" :
                launch == (std::launch::async | std::launch::deferred) ? "Default" :
                launch == std::launch::async ? "Async" : "?";
        }
    } // 'mutex' is released at 'critical_section' destruction time

    std::size_t size = 0;
    try {
		std::ifstream ifstream(_file_name, std::ios::binary | std::ios::in);
		assert(ifstream.is_open());
		std::filebuf* buffer = ifstream.rdbuf();
		assert(buffer);
		// Get file size by setting internal position to relative position and returns new position:
		size = buffer->pubseekoff(0, ifstream.end, ifstream.in);
		// Set internal position to absolute position (very beginning):
		std::size_t position = buffer->pubseekpos(0, ifstream.in);
		assert(position == 0);
		// Allocate 'memory' to contain file data
		char* memory = new char[size];
		// Fill in 'memory' with file data:
		buffer->sgetn(memory, size);
		// 'ifstream' is automatically closed at destruction time:
		// ifstream.close();
		// Write file data to stdout:
		std::cout.write(memory, size);
		delete[] memory;
    }
    catch (std::ifstream::failure & failure) { … }

    std::string end = launch == std::launch::deferred ? "Deferred" :
        launch == (std::launch::async | std::launch::deferred) ? "Default" :
        launch == std::launch::async ? "Async" : "?";
    end += " (end)";
    {
        const std::lock_guard<std::mutex> critical_section(_Mutex);
        _End.push_back(launch);
        for (std::launch launch : _Start) {
            end += " < ";
            end += launch == std::launch::deferred ? "Deferred" :
                launch == (std::launch::async | std::launch::deferred) ? "Default" :
                launch == std::launch::async ? "Async" : "?";
        }
    } // 'mutex' is released at 'critical_section' destruction time

    return start + " *** " + end;
}
…
Image image("Franck.jpg");
// Passed functions are each executed in a separate thread:
std::future<std::string> deferred_f = std::async(std::launch::deferred, std::bind(&Image::process, image, std::launch::deferred));
std::future<std::string> default_f = std::async(std::bind(&Image::process, image, std::launch::async | std::launch::deferred));
std::future<std::string> async_f = std::async(std::launch::async, std::bind(&Image::process, image, std::launch::async));

std::string async_s = async_f.get(); // Blocking...
std::string deferred_s = deferred_f.get(); // Blocking...
std::string default_s = default_f.get(); // Blocking...

std::cout << deferred_s << std::endl;
std::cout << default_s << std::endl;
std::cout << async_s << std::endl;

Promise

Rule(s)
  • The idea of “promise” pervades all programming language. It basically simplifies, even removes, the direct utilization of threads (“join” operations in particular). It is the best straightforward way of asynchronous programming for stream programming, big data processing, etc.
Example Promise.Cpp.zip 
// '.h' file:
#include <future> // 'std::promise'...
#include <string>

class Promise {
    std::promise<std::string> _p;
public:
    Promise();
    void request_Resource(std::string&&);
    std::string get_Resource();
};

// '.cpp' file:
Promise::Promise() {
    std::time_t t;
    // See also 'std::default_random_engine' at https://en.cppreference.com/w/cpp/numeric/random
    std::srand(static_cast<unsigned>(std::time(&t))); // Setup random suite...
}

std::string Promise::get_Resource() {
    std::future<std::string> f = _p.get_future(); // Blocking!
    std::string resource_name = f.get();
    std::cout << "'get_Resource' ends for " << resource_name << std::endl;
    return resource_name;
}

void Promise::request_Resource(std::string&& resource_name) {
    // This is a job that takes time to compute some value...
    int wait_for = std::abs(std::rand() % 5000 + 1); // Between 1 and 5000...
    std::cout << "Wait for " << wait_for << " ms about: " << resource_name << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(wait_for));
    _p.set_value(resource_name); // Job ends... '_p.get_future();' is unblocked...
}
…
Promise franck, barbier;
franck.request_Resource("Franck");
barbier.request_Resource("Barbier");
std::cout << franck.get_Resource() + barbier.get_Resource() << std::endl;
See also
Concepts in C++20 are constraints on types. They are specifically useful for checking the mixing of inheritance and genericity.
Example
// #include <concepts>
template <typename T> concept Is_Vegetable = requires {std::is_base_of_v<Vegetable, T>};
template<Is_Vegetable V> class Garden_;