diff --git a/chapter_03/examples/CMakeLists.txt b/chapter_03/examples/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2d5c64a0cd2c6875c949ebb70926a71cb2f066ee
--- /dev/null
+++ b/chapter_03/examples/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.28)
+set(CMAKE_CXX_EXTENSIONS OFF)
+set(CMAKE_CXX_STANDARD 23)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+project(cxx_course_examples CXX)
+
+
+FILE (GLOB sources ./ *.cc)
+foreach(source ${sources})
+    get_filename_component(withoutext "${source}" NAME_WE)
+    add_executable("${withoutext}" "${source}")
+endforeach()
+
+
diff --git a/chapter_03/examples/addables.cc b/chapter_03/examples/addables.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0227058f45b08e0dacf0560f2b70af99cd14c207
--- /dev/null
+++ b/chapter_03/examples/addables.cc
@@ -0,0 +1,23 @@
+#include <iostream>
+#include <string>
+#include <concepts>
+
+template <class T>
+concept Addable = requires(T a, T b) {
+    { a + b } -> std::convertible_to<T>;
+};
+
+auto aggregate(Addable auto... args)
+{
+    return (args + ...);
+}
+
+auto main() -> int
+{
+    using namespace std::string_literals;
+    std::cout << "aggregate(1, 2, 3, 4, 5) = "
+              << aggregate(1, 2, 3, 4, 5) << "\n";
+    std::cout << R"aw(aggregate("|-"s, "-|"s) = )aw"
+                << aggregate("|-"s, "-|"s) << "\n";
+}
+
diff --git a/chapter_03/examples/fold_xpr_demo2.cc b/chapter_03/examples/fold_xpr_demo2.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6750d6471068be3bd18f4b1d77b3296fce7e4297
--- /dev/null
+++ b/chapter_03/examples/fold_xpr_demo2.cc
@@ -0,0 +1,25 @@
+#include <iostream>
+#include <string>
+#include <vector>
+
+auto add_up(auto... args)
+{
+    return (args + ...);
+}
+
+template <typename T>
+void push_back(std::vector<T> &v, auto ... args) {
+    (v.push_back(args), ...);
+}
+
+auto main() -> int
+{
+    using namespace std;
+    string firstname{ "Steve" }, lastname{ "Rogers" };
+    cout << add_up(1, 2, 3, 4, 5) << "\n";
+    cout << add_up(firstname, " ", lastname) << "\n";
+
+    std::vector<double> q{0.0};
+    push_back(q, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8);
+    for (auto d : q) cout << d << "\n";
+}
diff --git a/chapter_03/examples/fold_xpr_demo3.cc b/chapter_03/examples/fold_xpr_demo3.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2c7f4c3ae73a6c92eba1cfac75b920ae7e5ce257
--- /dev/null
+++ b/chapter_03/examples/fold_xpr_demo3.cc
@@ -0,0 +1,20 @@
+#include <vector>
+#include <iostream>
+#include <algorithm>
+#include <ranges>
+#include <string>
+#include "print_tuple.hh"
+
+auto max_of_multiple(auto ... containers)
+{
+    return std::make_tuple(std::ranges::max(containers) ...);
+}
+
+auto main() -> int
+{
+    std::vector v1{8.2, 84., 9.1, 33.1, 9.33, 8.2, 8.3};
+    std::vector v2{9,1,2,8,3,1,4,2,0,8,1};
+    std::vector<std::string> v3{"Compact", "code", "with", "fold", "expressions"};
+    std::cout << max_of_multiple(v1, v2, v3) << "\n";
+}
+
diff --git a/chapter_03/examples/fold_xpr_demo4.cc b/chapter_03/examples/fold_xpr_demo4.cc
new file mode 100644
index 0000000000000000000000000000000000000000..bd916005dc0a2f313464584596f9d86ec006d03f
--- /dev/null
+++ b/chapter_03/examples/fold_xpr_demo4.cc
@@ -0,0 +1,32 @@
+#include <vector>
+#include <iostream>
+#include <ranges>
+#include <algorithm>
+#include "range_output.hh"
+
+auto conv(const std::vector<double>& inp, auto ... shift)
+{
+    namespace sr = std::ranges;
+    namespace sv = std::views;
+    std::vector<double> out(inp.size(), 0.);
+    auto res_exp = sv::iota(0, static_cast<int>(inp.size())) 
+        | sv::transform([inp, shift...](auto index){
+            auto S = inp.size();
+            return (inp[(index + shift) > 0 ? (index + shift) % S : S + (index + shift) % S] + ...) 
+                    / (sizeof ... (shift));
+        }); 
+
+    sr::copy(res_exp, out.begin());
+    return out;
+}
+
+auto main() -> int
+{
+    std::vector v(21UL, 0.);
+    v[10] = 1.0;
+    for (auto i = 0UL; i < 10; ++i) {
+        v = conv(v, 0, 1, 2);
+        std::cout << "After round " << i << ", v = " << output::comma_separated << v << "\n";
+    }
+}
+
diff --git a/chapter_03/examples/foldex.cc b/chapter_03/examples/foldex.cc
new file mode 100644
index 0000000000000000000000000000000000000000..dfc8ed5793f388c5108d99e2c8eb74d5274a2b38
--- /dev/null
+++ b/chapter_03/examples/foldex.cc
@@ -0,0 +1,27 @@
+#include <iostream>
+#include <string>
+#include <vector>
+
+template <typename... Args>
+auto add_up(Args... args)
+{
+    return (args + ...);
+}
+
+template <typename T, typename... Args>
+void push_back(std::vector<T> &v, Args ... args) {
+    (v.push_back(args), ...);
+}
+
+auto main() -> int
+{
+    using namespace std;
+    string firstname{ "Stephen" }, lastname{ "Hawking" };
+    cout << add_up(1, 2, 3, 4, 5) << "\n";
+    cout << add_up(firstname, " ", lastname) << "\n";
+
+    std::vector<double> q{0.0};
+    push_back(q, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8);
+    for (auto d : q) cout << d << "\n";
+}
+
diff --git a/chapter_03/examples/foldex_3.cc b/chapter_03/examples/foldex_3.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fad515b1b5f2fbab22200fcf6f81443e606fc6be
--- /dev/null
+++ b/chapter_03/examples/foldex_3.cc
@@ -0,0 +1,13 @@
+// examples/foldex_3.cc
+#include <algorithm>
+template <class First, class... Args>
+auto min(First first, Args... args)
+{
+    First retval = first;
+    ((retval = std::min(retval, args)), ...);
+    return retval;
+}
+int main()
+{
+    return min(8, 3, 4, 7, 2, 7) + min(2, 3, 9, 1);
+}
diff --git a/chapter_03/examples/gcd_w_concepts.cc b/chapter_03/examples/gcd_w_concepts.cc
new file mode 100644
index 0000000000000000000000000000000000000000..71bcb5cf3a2b26335ad9053496acfae8ae3692dc
--- /dev/null
+++ b/chapter_03/examples/gcd_w_concepts.cc
@@ -0,0 +1,18 @@
+#include <iostream>
+#include <type_traits>
+
+template <class T>
+concept Integral = std::is_integral_v<T>;
+
+constexpr auto gcd(Integral auto a, Integral auto b)
+{
+    if (b == 0)
+        return a;
+    return gcd(b, a % b);
+}
+auto main() -> int
+{
+    // Wont compile, until both the following arguments
+    // are changed into integral types.
+    std::cout << gcd(149935, 47295.) << "\n";
+}
diff --git a/chapter_03/examples/generic_func1.cc b/chapter_03/examples/generic_func1.cc
new file mode 100644
index 0000000000000000000000000000000000000000..def161da752c0ab975437934a4755a4b7e324ec2
--- /dev/null
+++ b/chapter_03/examples/generic_func1.cc
@@ -0,0 +1,25 @@
+#include <iostream>
+#include <string>
+
+auto f(auto i1, auto i2)
+{
+    return i1 + i2;
+}
+
+// Same as above, but enforce that the parameters have the same type
+template <class T>
+auto g(T i1, T i2)
+{
+    return i1 + i2;
+}
+
+int main()
+{
+    using namespace std::string_literals;
+    std::cout << f(1, 2) << "\n";
+    std::cout << f(1.2, 2.2) << "\n";
+    std::cout << f("1"s, "2"s) << "\n";
+    //std::cout << f("1"s, 2) << "\n"; // Does not work
+    std::cout << g("1"s, 2) << "\n"; // Does not work, but better errors
+}
+
diff --git a/chapter_03/examples/generic_func2.cc b/chapter_03/examples/generic_func2.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a3d3b7fd833f673be6b363517bb5664da76ea0b0
--- /dev/null
+++ b/chapter_03/examples/generic_func2.cc
@@ -0,0 +1,24 @@
+#include <iostream>
+#include <string>
+
+// Same as above, but enforce that the parameters have the same type
+template <class T>
+auto f(T i1, T i2)
+{
+    return i1 + i2;
+}
+
+auto main() -> int
+{
+    using namespace std::string_literals;
+    std::cout << f("1", "2") << "\n"; 
+    // Does not work, because it's an invalid use of the function f. We wrote that for things which are addable.
+    // How did we try to indicate this intention of "addability" of the arguments ?
+    // Answer : We didn't!
+    // If the function had been 50 lines instead of 1, the real error would be very hard to
+    // decipher. There is an assumption regarding incoming arguments in our function template,
+    // and we did not specify that assumption anywhere. How does one indicate such constraints ?
+    // Answer(C++20) : concepts
+    // Answer(C++ < C++20) : std::enable_if, type_traits and some acrobatic programming.
+}
+
diff --git a/chapter_03/examples/generic_func3.cc b/chapter_03/examples/generic_func3.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d152a8cf1486ae6eec10405532aba040bcd2aa8d
--- /dev/null
+++ b/chapter_03/examples/generic_func3.cc
@@ -0,0 +1,22 @@
+#include <iostream>
+#include <string>
+#include <concepts>
+
+template <class T>
+concept Addable = requires(T a, T b) {
+    { a + b } -> std::convertible_to<T>;
+};
+
+auto f(Addable auto i1, Addable auto i2)
+{
+    return i1 + i2;
+}
+
+int main()
+{
+    using namespace std::string_literals;
+    std::cout << f(1, 2) << "\n"; 
+    std::cout << f("1"s, "2"s) << "\n"; 
+    std::cout << f("1", "2") << "\n"; 
+}
+
diff --git a/chapter_03/examples/generic_func4.cc b/chapter_03/examples/generic_func4.cc
new file mode 100644
index 0000000000000000000000000000000000000000..79b252948079ab42c380b3211cdb3d8e75f19d56
--- /dev/null
+++ b/chapter_03/examples/generic_func4.cc
@@ -0,0 +1,31 @@
+#include <iostream>
+#include <string>
+
+template <class T>
+concept Addable = requires(T a, T b) {
+    { a + b } ;
+};
+
+
+template <class T> concept NotAddable = not Addable<T>;
+
+auto f(Addable auto i1, Addable auto i2)
+{
+    std::cout << "(using version of function f with Addable parameters) ... ";
+    return i1 + i2;
+}
+
+auto f(NotAddable auto i1, NotAddable auto i2)
+{
+    std::cout << "(using version of function f with NotAddable parameters) ... ";
+    return i1;
+}
+
+int main()
+{
+    using namespace std::string_literals;
+    std::cout << "f(1, 2) --> " << f(1, 2) << "\n"; 
+    std::cout << R"(f("1"s, "2"s) --> )" << f("1"s, "2"s) << "\n"; 
+    std::cout << R"(f("1", "2") --> )" << f("1", "2") << "\n"; 
+}
+
diff --git a/chapter_03/examples/no_textsub.cc b/chapter_03/examples/no_textsub.cc
new file mode 100644
index 0000000000000000000000000000000000000000..64e5097e3156445db8f2e1b7b83e0614e94634a4
--- /dev/null
+++ b/chapter_03/examples/no_textsub.cc
@@ -0,0 +1,12 @@
+template <unsigned N> constexpr unsigned fact = N * fact<N-1>;
+template <> constexpr unsigned fact<0> = 1U;
+static_assert(fact<7> == 5040);
+template <class A, class B>
+constexpr auto are_same = false;
+template <class A>
+constexpr auto are_same<A, A> = true;
+//static_assert(are_same<int, unsigned int>);
+using Integer = int;
+static_assert(are_same<int, Integer>);
+auto main() -> int {}
+
diff --git a/chapter_03/examples/overload_w_concepts.cc b/chapter_03/examples/overload_w_concepts.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a7fcbc6ebd5b3051ae3c50299a2725480b4e9a1f
--- /dev/null
+++ b/chapter_03/examples/overload_w_concepts.cc
@@ -0,0 +1,28 @@
+// examples/overload_w_concepts.cc
+#include <print>
+#include <concepts>
+#include <string>
+#include <typeinfo>
+
+template <class N> concept Number = std::is_floating_point_v<N> || std::is_integral_v<N>;
+template <class N> concept NotNumber = not Number<N>; 
+
+void proc(Number auto&& x) 
+{
+    std::print("Called proc for numbers with {} of typeid {}\n", x, typeid(x).name());
+}
+void proc(NotNumber auto&& x) 
+{
+    std::print("Called proc for non-numbers with {} of typeid {}\n", x, typeid(x).name());
+}
+
+auto main() -> int
+{
+    using namespace std::string_literals;
+    proc(-1);
+    proc(88UL);
+    proc("0118 999 88191 9119725 3");
+    proc(3.141);
+    proc("eighty"s);
+}
+
diff --git a/chapter_03/examples/print_tuple.cc b/chapter_03/examples/print_tuple.cc
new file mode 100644
index 0000000000000000000000000000000000000000..17a155af0e22bd60a4f24adac782ec9eaedd6966
--- /dev/null
+++ b/chapter_03/examples/print_tuple.cc
@@ -0,0 +1,33 @@
+#include <iostream>
+#include <string>
+#include <tuple>
+
+template <int idx, int MAX, typename... Args>
+struct PRINT_TUPLE {
+    static void print(std::ostream& strm, const std::tuple<Args...>& t)
+    {
+        strm << std::get<idx>(t) << (idx + 1 == MAX ? "" : ", ");
+        PRINT_TUPLE<idx + 1, MAX, Args...>::print(strm, t);
+    }
+};
+
+template <int MAX, typename... Args>
+struct PRINT_TUPLE<MAX, MAX, Args...> {
+    static void print(std::ostream& strm, const std::tuple<Args...>& t)
+    {
+    }
+};
+
+template <typename... Args>
+std::ostream& operator<<(std::ostream& strm, const std::tuple<Args...>& t)
+{
+    strm << "[";
+    PRINT_TUPLE<0, sizeof...(Args), Args...>::print(strm, t);
+    return strm << "]";
+}
+
+auto main() -> int
+{
+    std::tuple<int, std::string, double, int, double > t{23,"abc",3.141, 3, 2.718};
+    std::cout << t << "\n";
+}
diff --git a/chapter_03/examples/print_tuple_cxx17.cc b/chapter_03/examples/print_tuple_cxx17.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d45bfc0c5676caa45461ab225495ee1c0992fdfb
--- /dev/null
+++ b/chapter_03/examples/print_tuple_cxx17.cc
@@ -0,0 +1,32 @@
+#include <iostream>
+#include <string>
+#include <tuple>
+
+template <int idx, int MAX, typename... Args>
+struct PRINT_TUPLE {
+    static void print(std::ostream& strm, const std::tuple<Args...>& t)
+    {
+        if
+            constexpr(idx < MAX)
+            {
+                strm << std::get<idx>(t);
+                if
+                    constexpr((idx + 1) < MAX) strm << ", ";
+                PRINT_TUPLE<idx + 1, MAX, Args...>::print(strm, t);
+            }
+    }
+};
+
+template <typename... Args>
+auto operator<<(std::ostream& strm, const std::tuple<Args...>& t) -> std::ostream&
+{
+    strm << "[";
+    PRINT_TUPLE<0, sizeof...(Args), Args...>::print(strm, t);
+    return strm << "]";
+}
+
+auto main() -> int
+{
+    std::tuple<int, std::string, double, int, double> t{ 23, "abc", 3.141, 3, 2.718 };
+    std::cout << t << "\n";
+}
diff --git a/chapter_03/examples/print_tuple_cxx23.cc b/chapter_03/examples/print_tuple_cxx23.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3060f04eda623f403aae090c0cfdc48ef7961493
--- /dev/null
+++ b/chapter_03/examples/print_tuple_cxx23.cc
@@ -0,0 +1,11 @@
+#include <print>
+#include <tuple>
+#include <string_view>
+
+auto main() -> int
+{
+    using namespace std::literals;
+    std::tuple t{0.1, 11, "eleven hundred"sv};
+    std::print("{}\n", t);
+}
+
diff --git a/chapter_03/examples/print_tuple_foldex.cc b/chapter_03/examples/print_tuple_foldex.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2483331ba8a14cf176596c2d19612807523d56ad
--- /dev/null
+++ b/chapter_03/examples/print_tuple_foldex.cc
@@ -0,0 +1,31 @@
+#include <tuple>
+#include <iostream>
+#include <iomanip>
+
+template <class ... Args>
+auto operator<<(std::ostream & strm, const std::tuple<Args...> & t) -> std::ostream & 
+{
+    using namespace std;
+    auto print_one = [&strm](const auto & onearg) -> ostream & {
+        using bare_type = remove_cv_t<remove_reference_t<decltype(onearg)>>;
+        if constexpr (is_same_v<bare_type, string>)
+            strm << quoted(onearg);
+        else
+            strm << onearg;
+        return strm;
+    };
+    auto print_components = [&](const auto & ... args){
+       ((print_one(args) << ", "), ...);
+    };
+    strm << "[";
+    apply(print_components, t);
+    return strm <<"]";
+}
+
+auto main() -> int
+{
+    std::tuple t1{1, "one"};
+    std::tuple t2{2, "two", "II", 2.0};
+    std::cout << t1 << "\t" << t2 << "\n";
+}
+
diff --git a/chapter_03/examples/static_assert0.cc b/chapter_03/examples/static_assert0.cc
new file mode 100644
index 0000000000000000000000000000000000000000..08577af5b798c11e14683a1952180d0ba5aed1f2
--- /dev/null
+++ b/chapter_03/examples/static_assert0.cc
@@ -0,0 +1,7 @@
+auto advance(unsigned long L) -> double
+{
+    static_assert(sizeof(L) >= 8, "long must be at least 8 bytes. ");
+    //Bit manipulation assuming "long" is at least 8 bytes
+    return static_cast<double>(L);
+}
+auto main() -> int {}
diff --git a/chapter_03/examples/static_assert1.cc b/chapter_03/examples/static_assert1.cc
new file mode 100644
index 0000000000000000000000000000000000000000..47821a22502f7709b9413362f83b32e95fafe86d
--- /dev/null
+++ b/chapter_03/examples/static_assert1.cc
@@ -0,0 +1,7 @@
+auto advance(unsigned long i) -> double
+{
+    static_assert(sizeof(i) >= 8, "long must be bigger than 8 bytes");
+    return 0.;
+}
+auto main() -> int {}
+
diff --git a/chapter_03/examples/static_assert2.cc b/chapter_03/examples/static_assert2.cc
new file mode 100644
index 0000000000000000000000000000000000000000..df5d76d06a603ef407e6b95c5f9bc7ea20901ebb
--- /dev/null
+++ b/chapter_03/examples/static_assert2.cc
@@ -0,0 +1,23 @@
+#include <iostream>
+#include <type_traits>
+
+template < class T >
+struct SomeCalc
+{
+  static_assert(std::is_arithmetic<T>::value,"argument T must be an arithmetic type");
+  constexpr SomeCalc() {}
+  constexpr auto operator()(const T & t1, const T & t2) const ->decltype(t1+t2)
+  {
+    return t1+t2+1; // Let's say there is a bug in the implementation 
+  }
+};
+
+auto main() -> int
+{
+  constexpr SomeCalc<int> intadder;
+  constexpr int res = intadder(1,1);
+  static_assert(res == 2,"Adder seems to return unexpected result");
+  SomeCalc<std::string> stradder;
+}
+
+
diff --git a/chapter_03/examples/template_intro.cc b/chapter_03/examples/template_intro.cc
new file mode 100644
index 0000000000000000000000000000000000000000..78faceb817316cdeb6818dbddf3ed48482c5b1c2
--- /dev/null
+++ b/chapter_03/examples/template_intro.cc
@@ -0,0 +1,26 @@
+#include <iostream>
+
+template <class T>
+void copy(T* start, T* end, T* start2)
+{
+    for (; start != end; ++start, ++start2) {
+        *start2 = *start;
+    }
+}
+
+auto main() -> int
+{
+    double x[10], y[10];
+    for (auto& num : x)
+        num = 1;
+    copy(x, x + 10, y);
+    for (auto&& num : y)
+        std::cout << num << "\n";
+
+    std::string anames[5] = { "a", "b", "c", "d", "e" };
+    std::string bnames[5] = { " ", " ", " ", " ", " " };
+
+    copy(anames, anames + 5, bnames);
+    for (auto&& name : bnames)
+        std::cout << name << "\n";
+}
diff --git a/chapter_03/examples/variadic_1.cc b/chapter_03/examples/variadic_1.cc
new file mode 100644
index 0000000000000000000000000000000000000000..796578c0fb7a4dd64b7b489ff247aa709ee70a07
--- /dev/null
+++ b/chapter_03/examples/variadic_1.cc
@@ -0,0 +1,39 @@
+#include <iostream>
+#include <string>
+#if __has_include(<boost/type_index.hpp>)
+#include <boost/type_index.hpp>
+constexpr auto use_boost_type_index { true };
+#else
+#include <typeinfo>
+constexpr auto use_boost_type_index { false };
+#endif
+
+
+// plain_type_of(var) returns the typename without reference
+// symbols, const qualifiers etc.
+//
+template <class T>
+auto plain_type_of(T&& var) -> std::string
+{
+    if constexpr (use_boost_type_index)
+        return boost::typeindex::type_id<T>().pretty_name();
+    else
+        return typeid(var).name();
+}
+
+template <class... Types>
+void f(Types&&... args)
+{
+    std::cout << "Printing out typenames without references etc. and values\n";
+    ((std::cout << plain_type_of(args) << ": " << args << "\n"), ...);
+}
+
+auto main() -> int
+{
+    const int i { 3 }, j {};
+    size_t k {}, l { 9 };
+    const char* cst { "C-style string..." };
+    std::string cppst { "C++ string..." };
+    f(i, j, true, k, l, cst, cppst);
+}
+
diff --git a/chapter_03/examples/variadic_2.cc b/chapter_03/examples/variadic_2.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c388ce9ae2c371e255f2a0d2ea256db0a8f6ee65
--- /dev/null
+++ b/chapter_03/examples/variadic_2.cc
@@ -0,0 +1,27 @@
+#include <iostream>
+
+template <typename... Types>
+void f(Types... args);
+template <typename Type1, typename... Types>
+void f(Type1 arg1, Types... rest)
+{
+    std::cout << " The first argument is " << arg1
+              << ". Remainder argument list has " << sizeof...(Types) << " elements.\n";
+    f(rest...);
+}
+template <>
+void f() {}
+template <typename... Types>
+void g(Types... args)
+{
+    std::cout << "Inside g: going to call function f with the sizes of my arguments\n";
+    f(sizeof(args)...);
+}
+
+int main()
+{
+    std::cout << R"hoho(Calling f(0,true," 123 ");)hoho" << '\n';
+    f(0, true, "123");
+    std::cout << R"hoho(Calling g(0,true," 123 ");)hoho" << '\n';
+    g(0, true, "123");
+}
diff --git a/chapter_03/examples/variadic_3.cc b/chapter_03/examples/variadic_3.cc
new file mode 100644
index 0000000000000000000000000000000000000000..249c68b8c42648847c7453650a13b7705fcc7253
--- /dev/null
+++ b/chapter_03/examples/variadic_3.cc
@@ -0,0 +1,36 @@
+#include <array>
+#include <iostream>
+#include <list>
+#include <numeric>
+
+template <class... Types>
+void increment_all(Types&... args) { (++args, ...); }
+template <class... Ts>
+void h(Ts... args)
+{
+    std::cout << "Printing parameters passed to h \n";
+    ((std::cout << args << "\t"), ...);
+    std::cout << "\n";
+    [=, &args...] { return increment_all(args...); }();
+
+    std::cout << "\nModified value due to call to increment_all() through lambda \n";
+    ((std::cout << args << "\t"), ...);
+    std::cout << "\n";
+
+    std::cout << "Creating std::array out of parameters...\n";
+    std::array t { args... };
+
+    std::cout << "\nsum = " << std::reduce(t.begin(), t.end()) << "\n";
+}
+auto main() -> int
+{
+    int i = 0;
+    std::list l { 0, 2, 4, 8, 16 };
+    auto it = l.begin();
+    std::cout << "i = " << i << "; iterator it points to list element of value " << (*it) << "\n";
+    std::cout << "increment_all(i, it)\n";
+    increment_all(i, it);
+    std::cout << "i = " << i << "; iterator it points to list element of value " << (*it) << "\n";
+    std::cout << "Calling h(1, 2, 3, 4)\n";
+    h(1, 2, 3, 4);
+}
diff --git a/chapter_03/examples/variadic_3b.cc b/chapter_03/examples/variadic_3b.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7104b491262713169350a0f5902073acf16f9043
--- /dev/null
+++ b/chapter_03/examples/variadic_3b.cc
@@ -0,0 +1,67 @@
+#include <array>
+#include <iostream>
+#include <list>
+#include <numeric>
+#include <concepts>
+
+template <class T>
+concept Incrementable = requires(T ex) {
+    { ++ex };
+};
+
+template <Incrementable... Types>
+void increment_all(Types&... args) { (++args, ...); }
+
+// For function h() below, we can have as many parameters as
+// we want, but those parameters should all be of the same type.
+// To express this requirement, we create a variable template
+// AllSame_v<T...> which has a value true if all its template
+// parameters are true.
+//
+template <class... Ts>
+constexpr bool AllSame_v = true; // general template
+template <class First, class Second, class... Rest> 
+constexpr bool AllSame_v<First, Second, Rest...> // specialization
+    = std::is_same_v<First, Second> && AllSame_v<Second, Rest...>;
+
+// Now the concept AllSame can be expressed as follows
+template <class... Ts> concept AllSame = AllSame_v<Ts...>;
+
+template <class... Ts>
+void h(Ts&&... args) requires AllSame<Ts...>
+{
+    std::cout << "Printing parameters passed to h \n";
+    ((std::cout << args << "\t"), ...);
+    std::cout << "\n";
+    [=, &args...] { return increment_all(args...); }();
+
+    std::cout << "\nModified value due to call to increment_all() through lambda \n";
+    ((std::cout << args << "\t"), ...);
+    std::cout << "\n";
+
+    std::cout << "Creating std::array out of parameters...\n";
+    std::array t { args... };
+
+    std::cout << "\nsum = " << std::reduce(t.begin(), t.end()) << "\n";
+}
+
+auto main() -> int
+{
+    int i = 0;
+    std::list l { 0, 2, 4, 8, 16 };
+    auto it = l.begin();
+    std::cout << "i = " << i << "; iterator it points to list element of value " << (*it) << "\n";
+    std::cout << "increment_all(i, it)\n";
+    increment_all(i, it);
+    std::cout << "i = " << i << "; iterator it points to list element of value " << (*it) << "\n";
+    std::cout << "Calling h(1, 2, 3, 4)\n";
+    h(1, 2, 3, 4); // No problems!
+    // h(1, 2, 3, 4.); // Problems!
+    // h(i, 2, 3, 4); // Problems!
+    int j = 0;
+    h(i, j); // No problems!
+    const int k{7};
+    std::cout << "Introducing a constant integer k = " << k << "\n";
+    // h(k, k); // Problems!
+    // h(i, j, k); // Problems!
+}