diff --git a/day2/examples/collect.cc b/day2/examples/collect.cc new file mode 100644 index 0000000000000000000000000000000000000000..bc7f1f170a5a3fcf5bafdec509d858c5d0e5bc13 --- /dev/null +++ b/day2/examples/collect.cc @@ -0,0 +1,26 @@ +#include <iostream> +#include <vector> + +class collect { + std::vector<int> dat; +public: + auto operator|(int i) -> collect& + { + dat.push_back(i); + return *this; + } + auto operator~() const noexcept -> decltype(dat) + { + return dat; + } +}; +auto main() -> int +{ + auto C = collect{}; + C | 1 | 2 | 3 | 4 ; + for (auto el : (~C)) { + std::cout << el << "\n"; + } +} + + diff --git a/day2/examples/complex_number_class.cc b/day2/examples/complex_number_class.cc new file mode 100644 index 0000000000000000000000000000000000000000..5b73f634268af5807f70b408cb2831562c9d469b --- /dev/null +++ b/day2/examples/complex_number_class.cc @@ -0,0 +1,114 @@ +#include <iostream> + +class complex_number +{ +public: + // If the constructor is meant to do nothing, let the compiler generate it + constexpr complex_number() noexcept = default; + // Same for the destructor + ~complex_number() noexcept = default; + // Constructor with real and imaginary parts + constexpr complex_number(double re, double im) noexcept; + // Constructor with only a real part. It "delegates" its work to the + // constructor above. See its implementation below + constexpr complex_number(double re) noexcept; + // Copy constructor with trivial member wise copy + constexpr complex_number(const complex_number &c) noexcept = default; + // Trivial assignment operator + constexpr auto operator=(const complex_number& c) noexcept -> complex_number& = default; + // Move constructor with trivial member wise move + constexpr complex_number(complex_number &&c) noexcept = default; + // Move assignment operator + constexpr auto operator=(complex_number&& c) noexcept -> complex_number& = default; + // Arithmetic operators changing the calling object + constexpr auto operator+=(const complex_number&) noexcept -> complex_number&; + constexpr auto operator-=(const complex_number&) noexcept -> complex_number&; + constexpr auto operator*=(const complex_number&) noexcept -> complex_number&; + // Accessor functions + constexpr auto real() const noexcept -> double { return m_real; } + constexpr auto imag() const noexcept -> double { return m_imag; } + constexpr auto modulus() const noexcept -> double { return m_real * m_real + m_imag * m_imag; } + // Non-member function which accesses private data + // This is needed to write things like + // double d; complex_number c; + // complex_number e = d*c; + // Because the operator is called with the LHS as the refering object + friend constexpr auto operator*(double x, const complex_number&) noexcept -> complex_number; + // Teach ostream how to output your class + friend auto operator<<(std::ostream& os, const complex_number& c) -> std::ostream&; + +private: + // Data variables. Private. Initialised. + double m_real=0,m_imag=0; +}; +// Note syntax for initialisation. You can assign to m_real and m_imag in the +// function body, but the initialiser syntax is more compact. +constexpr complex_number::complex_number(double re, double im) noexcept : m_real{re},m_imag{im} {} +// This is a constructor which gets its work done by calling another constructor. +// This is allowed since C++11. +constexpr complex_number::complex_number(double re) noexcept : complex_number{re,0} {} +// Note the compact notation for the return statement. The "type" of the +// return value is, of course, known from the function signature. So, +// the compiler knows that it has to construct a complex_number from +// whatever that comes after the keyword "return". Since we have +// only a set of braces with two arguments, it looks for a constructor +// with two double arguments, and uses that. +// The following functions are not member functions. They don't need to be. +constexpr auto operator+(const complex_number& b, const complex_number& c) noexcept -> complex_number +{ + return {b.real()+c.real(),b.imag()+c.imag()}; +} +constexpr auto operator-(const complex_number& b, const complex_number& c) noexcept -> complex_number +{ + return {b.real()-c.real(),b.imag()-c.imag()}; +} +constexpr auto operator*(const complex_number& b, const complex_number& c) noexcept -> complex_number +{ + return {b.real()*c.real()-b.imag()*c.imag(), b.real()*c.imag() + b.imag()*c.real()}; +} +// Modifying operators do not construct a new object and return it, but +// instead directly change the data in the calling object. Look how +// the function returns the calling object through the "this" pointer! +// This is needed to write nested statements like z=z1*(z2+=z1); +constexpr auto complex_number::operator+=(const complex_number& c) noexcept -> complex_number& +{ + m_real+=c.m_real; + m_imag+=c.m_imag; + return *this; +} +constexpr auto complex_number::operator-=(const complex_number& c) noexcept -> complex_number& +{ + m_real-=c.m_real; + m_imag-=c.m_imag; + return *this; +} +constexpr auto complex_number::operator*=(const complex_number& c) noexcept -> complex_number& +{ + // Temporary store for new real value + double tmprl=m_real*c.m_real-m_imag*c.m_imag; + // Calculate new imaginary value using old real and imaginary parts + m_imag=m_real*c.m_imag+m_imag*c.m_real; + m_real=tmprl; + return *this; +} +constexpr auto operator*(double x, const complex_number& c) noexcept -> complex_number +{ + return {x*c.m_real,x*c.m_imag}; +} +auto operator<<(std::ostream& os, const complex_number& c) -> std::ostream& +{ + os << c.m_real; + if (c.m_imag>0) os << '+'; + os << c.m_imag << 'i'; + return os; +} + +auto main() -> int +{ + static_assert(complex_number { 0.1, -2.3 }.modulus() > 0, ""); + complex_number z0{0.3,0.84}, z; + for (int i=0; i<10; ++i) { + z = z*z + z0; + std::cout << z << "\n"; + } +} diff --git a/day2/examples/desig2.cc b/day2/examples/desig2.cc new file mode 100644 index 0000000000000000000000000000000000000000..89d4f4828c94cbd862ca9ba260033283b5a480d0 --- /dev/null +++ b/day2/examples/desig2.cc @@ -0,0 +1,16 @@ +#include <iostream> + +struct v3 { double x, y, z; }; +struct pars { int offset; v3 velocity; }; +std::ostream & operator<<(std::ostream & os, const v3 & v) { return os << v.x << ", " << v.y << ", " << v.z << " "; } +auto example_func(pars p) +{ + std::cout << p.offset << " with velocity " << p.velocity << "\n"; +} + +int main() +{ + example_func({.offset = 5, .velocity = {.x=1., .y = 2., .z=3.}}); +} + + diff --git a/day2/examples/exception.cc b/day2/examples/exception.cc new file mode 100644 index 0000000000000000000000000000000000000000..ad6a36692767e3ba48fed3db6e4977aa10229951 --- /dev/null +++ b/day2/examples/exception.cc @@ -0,0 +1,32 @@ +#include <iostream> +#include <stdexcept> + +double f(double x) +{ + double answer=1; + if (x>=0 and x<10) { + while (x>0) { + answer*=x; + x-=1; + } + } else { + throw(std::invalid_argument("Bad parameter value " + std::to_string(x))); + } + return answer; +} + + +int main() +{ + double x=9.0; + try { + std::cout<<"Enter start point : "; + std::cin >> x; + auto res=f(x); + std::cout <<"The result is "<<res<<'\n'; + } catch (std::exception &ex) { + std::cerr<<"Cought exception "<<ex.what()<<'\n'; + } +} + + diff --git a/day2/examples/gcd.cc b/day2/examples/gcd.cc new file mode 100644 index 0000000000000000000000000000000000000000..63ccfae22a9756596a4e5f5238a5e9187110c73b --- /dev/null +++ b/day2/examples/gcd.cc @@ -0,0 +1,24 @@ +#include <iostream> + +unsigned long euclid_gcd(unsigned long smaller, unsigned long larger) +{ + if (smaller > larger) + std::swap(smaller, larger); + while (smaller != 0) { + auto rem = larger % smaller; + larger = smaller; + smaller = rem; + } + return larger; +} + +int main(int argc, char* argv[]) +{ + if (argc != 3) { + std::cout << "Usage:\n" + << argv[0] << " number1 number2\n"; + return 1; + } + unsigned long n1 = std::stoul(argv[1]), n2 = std::stoul(argv[2]); + std::cout << euclid_gcd(n1, n2) << "\n"; +} diff --git a/day2/examples/literals.cc b/day2/examples/literals.cc new file mode 100644 index 0000000000000000000000000000000000000000..0f322cb8abdabd13dcb298556ea086f66ff58e2a --- /dev/null +++ b/day2/examples/literals.cc @@ -0,0 +1,34 @@ +#include <iostream> + +class Temperature +{ + double v = 0.0; + public: + enum class Unit { K, C }; + constexpr auto ConvFrom(double x, Unit u) { + switch (u) { + case Unit::K : return x; + case Unit::C : + default: return 273.15 + x; + }; + } + Temperature() = default; + Temperature(double x, Unit u) : v{ ConvFrom(x, u) } {} + auto Kelvin() const noexcept -> double { return v; } + auto Celsius() const noexcept -> double { return v; } +}; +auto operator "" _K(long double d) -> Temperature +{ + return { static_cast<double>(d), Temperature::Unit::K }; +} +auto operator "" _C(long double d) -> Temperature +{ + return { static_cast<double>(d), Temperature::Unit::C }; +} + +auto main() -> int +{ + auto T1 = 273.15_K; + auto T2 = 100.0_C; + std::cout << T1.Celsius() << "\t" << T2.Celsius() << "\n"; +} diff --git a/day2/examples/onexcept.cc b/day2/examples/onexcept.cc new file mode 100644 index 0000000000000000000000000000000000000000..38fbd6765c871045acc9bb0134daacc77130a420 --- /dev/null +++ b/day2/examples/onexcept.cc @@ -0,0 +1,25 @@ +#include "Vbose.hh" + +void testfunc(int i) +{ + std::cout << "Entering testfunc with argument " << i << "\n"; + Vbose v{"VFROMTESTFUNC"}; + if (i > 2) { + std::cout << "Exiting testfunc() via exception.\n"; + throw 2; + } + else std::cout << "Passed check point 2\n"; + std::cout << "Last line of testfunc("<< i << ")\n"; +} + +auto main() -> int +{ + try { + testfunc(0); + testfunc(1); + testfunc(3); + testfunc(2); + } catch (int err) { + std::cout << "Caught exception " << err << "\n"; + } +} diff --git a/day2/examples/op_overload.cc b/day2/examples/op_overload.cc new file mode 100644 index 0000000000000000000000000000000000000000..bb1fd103dc0c53d475b6ce6a2a8d98a2cf1291e4 --- /dev/null +++ b/day2/examples/op_overload.cc @@ -0,0 +1,31 @@ +#include <iostream> + +class A {}; +class B {}; + +auto operator+(A x, A y) -> A +{ + std::cout << "Called operator+() with two A type arguments\n"; + return x; +} +auto operator+(B x, B y) -> B +{ + std::cout << "Called operator+() with two B type arguments\n"; + return x; +} +auto operator@(A x, B y) -> A +{ + std::cout << "Called operator+() with one A type and one B type argument\n"; + return x; +} + +auto main() -> int +{ + A a1, a2; + B b1, b2; + a1 + a2; + a1 @ b1; + b1 + b2; +// b1 + a2; +} + diff --git a/day2/examples/sqrt_error_handling/mysqrt_expected.cc b/day2/examples/sqrt_error_handling/mysqrt_expected.cc new file mode 100644 index 0000000000000000000000000000000000000000..75d10d83bcd922ef4bfcb39dde408f0a5996c2b9 --- /dev/null +++ b/day2/examples/sqrt_error_handling/mysqrt_expected.cc @@ -0,0 +1,35 @@ +#include <cmath> +#include <expected> +#include <iostream> + +auto mysqrt(double x) -> std::expected<double, std::string> +{ + const auto eps = 1.0e-12; + const auto eps2 = eps * eps; + if (x >= 0.) { + auto r0 = 0.5 * (1. + x); + auto r1 = x / r0; + while ((r0 - r1) * (r0 - r1) > eps2) { + r0 = 0.5 * (r0 + r1); + r1 = x / r0; + } + return { r1 }; + } else { + return std::unexpected { "Unexpected input!" }; + } +} + +auto main() -> int +{ + double x {}; + std::cout << "Enter a positive real number: "; + std::cin >> x; + if (auto rm = mysqrt(x); rm) { + auto rs = std::sqrt(x); + std::cout << "Square root with own function = " << rm.value() << "\n"; + std::cout << "Square root with standard function = " << rs << "\n"; + std::cout << "Difference = " << rm.value() - rs << "\n"; + } else { + std::cout << "Square root did not return an expected value. Error: " << rm.error() << "\n"; + } +} diff --git a/day2/examples/sqrt_error_handling/mysqrt_expt0.cc b/day2/examples/sqrt_error_handling/mysqrt_expt0.cc new file mode 100644 index 0000000000000000000000000000000000000000..164f4c3b083816af9cc9028d7601e8a6fac45fa5 --- /dev/null +++ b/day2/examples/sqrt_error_handling/mysqrt_expt0.cc @@ -0,0 +1,36 @@ +#include <iostream> +#include <cmath> + +using error_code = int; + +auto mysqrt(double x) -> double +{ + const auto eps = 1.0e-12; + const auto eps2 = eps * eps; + if (x < 0) throw error_code{-1}; + auto r0 = 0.5 * (1. + x); + auto r1 = x / r0; + while ((r0 - r1) * (r0 - r1) > eps2) { + r0 = 0.5 * (r0 + r1); + r1 = x / r0; + } + return r1; +} + +auto main() -> int +{ + double x{}; + std::cout << "Enter a positive real number: "; + std::cin >> x; + try { + auto rm = mysqrt(x); + auto rs = std::sqrt(x); + std::cout << "Square root with own function = " << rm << "\n"; + std::cout << "Square root with standard function = " << rs << "\n"; + std::cout << "Difference = " << rm - rs << "\n"; + } catch (error_code& error) { + std::cout << "The input number needs to be positive.\n"; + std::cout << "Caught error_code with value " << error << "\n"; + } +} + diff --git a/day2/examples/sqrt_error_handling/mysqrt_expt1.cc b/day2/examples/sqrt_error_handling/mysqrt_expt1.cc new file mode 100644 index 0000000000000000000000000000000000000000..ff969b5a69e95abeedd054a3550935409ae8b3bd --- /dev/null +++ b/day2/examples/sqrt_error_handling/mysqrt_expt1.cc @@ -0,0 +1,36 @@ +#include <iostream> +#include <cmath> + +using error_code = std::string; + +auto mysqrt(double x) -> double +{ + const auto eps = 1.0e-12; + const auto eps2 = eps * eps; + if (x < 0) + throw error_code{"Asking for square root of a negative number, are you alright?" }; + auto r0 = 0.5 * (1. + x); + auto r1 = x / r0; + while ((r0 - r1) * (r0 - r1) > eps2) { + r0 = 0.5 * (r0 + r1); + r1 = x / r0; + } + return r1; +} + +auto main() -> int +{ + double x{}; + std::cout << "Enter a positive real number: "; + std::cin >> x; + try { + auto rm = mysqrt(x); + auto rs = std::sqrt(x); + std::cout << "Square root with own function = " << rm << "\n"; + std::cout << "Square root with standard function = " << rs << "\n"; + std::cout << "Difference = " << rm - rs << "\n"; + } catch (error_code& error) { + std::cout << "Caught error_code with value:\"" << error << "\"\n"; + } +} + diff --git a/day2/examples/sqrt_error_handling/mysqrt_expt2.cc b/day2/examples/sqrt_error_handling/mysqrt_expt2.cc new file mode 100644 index 0000000000000000000000000000000000000000..bf99b1043991ede2b8bee444ddafbaba3f5c0d9c --- /dev/null +++ b/day2/examples/sqrt_error_handling/mysqrt_expt2.cc @@ -0,0 +1,35 @@ +#include <stdexcept> +#include <iostream> +#include <cmath> + +auto mysqrt(double x) -> double +{ + const auto eps = 1.0e-12; + const auto eps2 = eps * eps; + if (x < 0) + throw std::runtime_error{"Asking for square root of a negative number, are you alright?" }; + auto r0 = 0.5 * (1. + x); + auto r1 = x / r0; + while ((r0 - r1) * (r0 - r1) > eps2) { + r0 = 0.5 * (r0 + r1); + r1 = x / r0; + } + return r1; +} + +auto main() -> int +{ + double x{}; + std::cout << "Enter a positive real number: "; + std::cin >> x; + try { + auto rm = mysqrt(x); + auto rs = std::sqrt(x); + std::cout << "Square root with own function = " << rm << "\n"; + std::cout << "Square root with standard function = " << rs << "\n"; + std::cout << "Difference = " << rm - rs << "\n"; + } catch (std::runtime_error& error) { + std::cout << "Caught runtime_error:\"" << error.what() << "\"\n"; + } +} + diff --git a/day2/examples/sqrt_error_handling/mysqrt_expt3.cc b/day2/examples/sqrt_error_handling/mysqrt_expt3.cc new file mode 100644 index 0000000000000000000000000000000000000000..bf99b1043991ede2b8bee444ddafbaba3f5c0d9c --- /dev/null +++ b/day2/examples/sqrt_error_handling/mysqrt_expt3.cc @@ -0,0 +1,35 @@ +#include <stdexcept> +#include <iostream> +#include <cmath> + +auto mysqrt(double x) -> double +{ + const auto eps = 1.0e-12; + const auto eps2 = eps * eps; + if (x < 0) + throw std::runtime_error{"Asking for square root of a negative number, are you alright?" }; + auto r0 = 0.5 * (1. + x); + auto r1 = x / r0; + while ((r0 - r1) * (r0 - r1) > eps2) { + r0 = 0.5 * (r0 + r1); + r1 = x / r0; + } + return r1; +} + +auto main() -> int +{ + double x{}; + std::cout << "Enter a positive real number: "; + std::cin >> x; + try { + auto rm = mysqrt(x); + auto rs = std::sqrt(x); + std::cout << "Square root with own function = " << rm << "\n"; + std::cout << "Square root with standard function = " << rs << "\n"; + std::cout << "Difference = " << rm - rs << "\n"; + } catch (std::runtime_error& error) { + std::cout << "Caught runtime_error:\"" << error.what() << "\"\n"; + } +} + diff --git a/day2/examples/sqrt_error_handling/mysqrt_opt.cc b/day2/examples/sqrt_error_handling/mysqrt_opt.cc new file mode 100644 index 0000000000000000000000000000000000000000..19790a8d38dcd62d8d655b5936e75ebbbf2a7181 --- /dev/null +++ b/day2/examples/sqrt_error_handling/mysqrt_opt.cc @@ -0,0 +1,36 @@ +#include <iostream> +#include <cmath> +#include <optional> + +auto mysqrt(double x) -> std::optional<double> +{ + std::optional<double> ans; + const auto eps = 1.0e-12; + const auto eps2 = eps * eps; + if (x >= 0.) { + auto r0 = 0.5 * (1. + x); + auto r1 = x / r0; + while ((r0 - r1) * (r0 - r1) > eps2) { + r0 = 0.5 * (r0 + r1); + r1 = x / r0; + } + ans = r1; + } + return ans; +} + +auto main() -> int +{ + double x{}; + std::cout << "Enter a positive real number: "; + std::cin >> x; + if (auto rm = mysqrt(x); rm) { + auto rs = std::sqrt(x); + std::cout << "Square root with own function = " << rm.value() << "\n"; + std::cout << "Square root with standard function = " << rs << "\n"; + std::cout << "Difference = " << rm.value() - rs << "\n"; + } else { + std::cout << "Square root does not contain a value. Bad input!\n"; + } +} + diff --git a/day2/examples/trivialclassoverload.cc b/day2/examples/trivialclassoverload.cc new file mode 100644 index 0000000000000000000000000000000000000000..f384557f92386eda50df8aa317d906121ba9c221 --- /dev/null +++ b/day2/examples/trivialclassoverload.cc @@ -0,0 +1,19 @@ +#include <iostream> +class A{}; +class B{}; + +void f(int i, A a) +{ + std::cout << "Called version with input types (int, A)\n"; +} +void f(int i, B b) +{ + std::cout << "Called version with input types (int, B)\n"; +} +auto main() -> int +{ + A xa; + B xb; + f(0, xa); + f(0, xb); +} diff --git a/day2/examples/verbose_ctordtor.cc b/day2/examples/verbose_ctordtor.cc new file mode 100644 index 0000000000000000000000000000000000000000..23beae7acbba274289e2bba7013447ac4a06213e --- /dev/null +++ b/day2/examples/verbose_ctordtor.cc @@ -0,0 +1,57 @@ +#include <iomanip> +#include <iostream> +#include <string> +#include "Vbose.hh" + +auto operator<<(std::ostream& os, const Vbose* obj) -> std::ostream& +{ + os << std::hex << (size_t)(obj); + return os; +} + +auto f(std::string a) -> Vbose +{ + std::cout << "Entering f()\n"; + Vbose tmp(a); + if (tmp.getval() == "") { + std::cerr << "Warning! Empty string used to construct object!\n"; + } + std::cout << "Leaving f()\n"; + return tmp; +} + +void g(Vbose v) +{ + std::cout << "Called g with " << &v << "(" << v.getval() << ")\n"; + v.setval(v.getval() + "_modified"); + std::cout << "g() : Modified v to " << v.getval() << "\n"; +} + +auto main() -> int +{ + std::cout << "Entering main()\n"; + std::cout << "Constructing a and b\n"; + Vbose a, b("Mercury"); + { + Vbose c("UnusedVar"); + } + std::cout << "Calling f and assigning result to a\n"; + a = f("Venus"); + + std::cout << "Calling f without assigning the result\n"; + f("Jupitor"); + std::cout << "Statement after calling f without assigning result\n"; + + std::cout << "Calling g with b\n"; + g(b); + std::cout << "Statement after calling g with b\n"; + std::cout << "Value of b, after call to g, is " << b.getval() << "\n"; + + std::cout << "Calling g with a+b\n"; + g(a + b); + + std::cout << "Calling g with std::move(a)\n"; + g(std::move(a)); + std::cout << "Leaving main()\n"; +} +