diff --git a/day3/ProgrammingInCXX_d3.pdf b/day3/ProgrammingInCXX_d3.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6cdb2d36c6a6029045422612e6422d35a1220ef7 Binary files /dev/null and b/day3/ProgrammingInCXX_d3.pdf differ diff --git a/day3/examples/gcd_w_concepts.cc b/day3/examples/gcd_w_concepts.cc new file mode 100644 index 0000000000000000000000000000000000000000..fc739673145381c813c1dca8b703dc25122c7a27 --- /dev/null +++ b/day3/examples/gcd_w_concepts.cc @@ -0,0 +1,17 @@ +#include <type_traits> +#include <iostream> + +template <class T> +concept Integral = std::is_integral_v<T>; + +constexpr auto gcd(Integral auto a, Integral auto b) { + if (b == 0) return a; + else 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/day3/examples/generic_func1.cc b/day3/examples/generic_func1.cc new file mode 100644 index 0000000000000000000000000000000000000000..def161da752c0ab975437934a4755a4b7e324ec2 --- /dev/null +++ b/day3/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/day3/examples/generic_func2.cc b/day3/examples/generic_func2.cc new file mode 100644 index 0000000000000000000000000000000000000000..4610e8bccfdc9e96fba1636f215c93f0013cae6e --- /dev/null +++ b/day3/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; +} + +int main() +{ + using namespace std::string_literals; + std::cout << f("1", "2") << "\n"; + // Does not work, because it's an invalid use for 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/day3/examples/generic_func3.cc b/day3/examples/generic_func3.cc new file mode 100644 index 0000000000000000000000000000000000000000..d152a8cf1486ae6eec10405532aba040bcd2aa8d --- /dev/null +++ b/day3/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/day3/examples/generic_func4.cc b/day3/examples/generic_func4.cc new file mode 100644 index 0000000000000000000000000000000000000000..79b252948079ab42c380b3211cdb3d8e75f19d56 --- /dev/null +++ b/day3/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/day3/examples/geometry/CMakeLists.txt b/day3/examples/geometry/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..47def0c0028b1da545cdd5912d1c08486bb386d2 --- /dev/null +++ b/day3/examples/geometry/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.14) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +project(geometry_exercise CXX) +add_executable(${PROJECT_NAME} Point.cc Triangle.cc Circle.cc main.cc) + diff --git a/day3/examples/geometry/Circle.cc b/day3/examples/geometry/Circle.cc new file mode 100644 index 0000000000000000000000000000000000000000..096797ea07e428a9923c263e6c5093b805765720 --- /dev/null +++ b/day3/examples/geometry/Circle.cc @@ -0,0 +1,31 @@ +#include "Circle.hh" + +constexpr double pi = 3.141592653589793; + +Circle::Circle(double rad, const Point& p) + : r{ rad } + , c{ p } +{ +} + +auto Circle::name() const -> std::string +{ + return "Circle"; +} + +auto Circle::area() const -> double +{ + return pi * r * r; +} + +auto Circle::perimeter() const -> double +{ + return 2 * pi * r; +} + +void Circle::rotate(double phi) { phi = 0; } + +void Circle::translate(Point p) +{ + c += p; +} diff --git a/day3/examples/geometry/Circle.hh b/day3/examples/geometry/Circle.hh new file mode 100644 index 0000000000000000000000000000000000000000..615df31fa0c566eb206998cdf747c1fedacbc0e4 --- /dev/null +++ b/day3/examples/geometry/Circle.hh @@ -0,0 +1,27 @@ +#ifndef Circle_HH +#define Circle_HH +#include "Point.hh" +#include "Shape.hh" +#include <string> + +class Circle : public Shape { +public: + Circle() = default; + Circle(double rad, const Point& p); + Circle(const Circle& cir) = default; + Circle(Circle&& cir) = default; + auto operator=(const Circle& cir) -> Circle& = default; + auto operator=(Circle&& cir) -> Circle& = default; + void rotate(double phi) override; + void translate(Point p) override; + auto area() const -> double override; + auto perimeter() const -> double override; + inline auto circumference() const -> double { return perimeter(); } + auto name() const -> std::string override; + +private: + double r{ 1.0 }; + Point c{}; // Use default constructor of class Point to create c +}; + +#endif diff --git a/day3/examples/geometry/Point.cc b/day3/examples/geometry/Point.cc new file mode 100644 index 0000000000000000000000000000000000000000..1b10c867b1b106653270eb7613a3ebc0f4332b5a --- /dev/null +++ b/day3/examples/geometry/Point.cc @@ -0,0 +1,53 @@ +#include "Point.hh" +#include <iostream> + +Point::Point(double x, double y) + : X{ x } + , Y{ y } +{ +} + +auto Point::operator+=(const Point& p) -> Point& +{ + X += p.X; + Y += p.Y; + return *this; +} + +auto Point::operator-=(const Point& p) -> Point& +{ + X -= p.X; + Y -= p.Y; + return *this; +} + +auto Point::operator+(const Point& p) const -> Point +{ + return { X + p.X, Y + p.Y }; +} + +auto Point::operator-(const Point& p) const -> Point +{ + return { X - p.X, Y - p.Y }; +} + +auto Point::operator*(const Point& p) const -> double +{ + return (X * p.X + Y * p.Y); +} + +auto Point::operator*(double f) const -> Point +{ + return { f * X, f * Y }; +} + +auto operator*(double f, const Point& p) -> Point +{ + return { f * p.X, f * p.Y }; +} + +auto operator<<(std::ostream& os, const Point& p) -> std::ostream& +{ + os << "(" << p.X << ", " << p.Y << ")"; + return os; +} diff --git a/day3/examples/geometry/Point.hh b/day3/examples/geometry/Point.hh new file mode 100644 index 0000000000000000000000000000000000000000..b68b4d4e9575f68705961df1eb8d8adddaf6676b --- /dev/null +++ b/day3/examples/geometry/Point.hh @@ -0,0 +1,23 @@ +#ifndef Point_HH +#define Point_HH +class ostream; +struct Point { + double X = 0, Y = 0; + Point() = default; + Point(const Point&) = default; + Point(Point&&) = default; + auto operator=(const Point& p) -> Point& = default; + auto operator=(Point&& p) -> Point& = default; + Point(double x, double y); + auto operator+=(const Point& p) -> Point&; + auto operator-=(const Point& p) -> Point&; + auto operator+(const Point& p) const -> Point; + auto operator-(const Point& p) const -> Point; + auto operator*(const Point& p) const -> double; + auto operator*(double f) const -> Point; +}; + +auto operator*(double f, const Point& p) -> Point; +auto operator<<(ostream& os, const Point& p) -> ostream&; + +#endif diff --git a/day3/examples/geometry/Polygon.hh b/day3/examples/geometry/Polygon.hh new file mode 100644 index 0000000000000000000000000000000000000000..293c82ac8b4efef79399e26f1c8e75f714dc5650 --- /dev/null +++ b/day3/examples/geometry/Polygon.hh @@ -0,0 +1,50 @@ +#ifndef Polygon_HH +#define Polygon_HH +#include <array> +#include <cmath> +#include "Shape.hh" + +template <unsigned int NV> +class Polygon : public Shape { + static_assert(NV > 2, "Can't have polygon with less than 3 sides"); +public: + Polygon() = default; + Polygon(const Polygon&) = default; + Polygon(Polygon&&) = default; + auto operator=(const Polygon& pg) -> Polygon& = default; + auto operator=(Polygon &&) -> Polygon& = default; + constexpr auto n_vertexes() const { return NV; } + auto name() const -> std::string override { return "Polygon<" + std::to_string(NV) + ">"; } + + auto perimeter() const -> double override + { + double ans = 0; + for (size_t i = 1; i < vertex.size(); ++i) { + ans += sqrt((vertex[i] - vertex[i - 1]) * (vertex[i] - vertex[i - 1])); + } + ans += sqrt((vertex.front() - vertex.back()) * (vertex.front() - vertex.back())); + return ans; + } + void translate(Point p) override { + for (auto& pt : vertex) + pt += p; + } + + void rotate(double phi) override{ + Point center; + for (auto pt : vertex) + center += pt; + center = (1.0 / NV) * center; + double ct = cos(phi), st = sin(phi); + for (auto& pt : vertex) { + auto rel = pt - center; + pt = center + Point(ct * rel.X + st * rel.Y, -st * rel.X + ct * rel.Y); + } + } + + +protected: + std::array<Point, NV> vertex; +}; + +#endif diff --git a/day3/examples/geometry/Shape.hh b/day3/examples/geometry/Shape.hh new file mode 100644 index 0000000000000000000000000000000000000000..52c9289897cb6405d3503d756e3731946f97e16b --- /dev/null +++ b/day3/examples/geometry/Shape.hh @@ -0,0 +1,17 @@ +#ifndef Shape_HH +#define Shape_HH + +#include "Point.hh" +#include <string> + +class Shape { +public: + virtual ~Shape() = default; + virtual void rotate(double) = 0; + virtual void translate(Point) = 0; + virtual auto area() const -> double = 0; + virtual auto perimeter() const -> double = 0; + virtual auto name() const -> std::string = 0; +}; + +#endif diff --git a/day3/examples/geometry/Triangle.cc b/day3/examples/geometry/Triangle.cc new file mode 100644 index 0000000000000000000000000000000000000000..c3f484c1f84b9001a11fb627cd0c4f02768eac00 --- /dev/null +++ b/day3/examples/geometry/Triangle.cc @@ -0,0 +1,23 @@ +#include "Triangle.hh" +#include <cmath> +// A "static" function in a source file (not a static member function of a class) +// is meant to be visible only in the same translation unit, most often just that +// source file. +static inline auto sqr(Point p) -> double { return p * p; } + +Triangle::Triangle(Point p1, Point p2, Point p3) + : Polygon<3>{} +{ + vertex[0] = p1; + vertex[1] = p2; + vertex[2] = p3; +} + +auto Triangle::area() const -> double +{ + double s = 0.5 * perimeter(); + double a = sqrt(sqr(vertex[0] - vertex[1])); + double b = sqrt(sqr(vertex[0] - vertex[2])); + double c = sqrt(sqr(vertex[1] - vertex[2])); + return sqrt(s * (s - a) * (s - b) * (s - c)); +} diff --git a/day3/examples/geometry/Triangle.hh b/day3/examples/geometry/Triangle.hh new file mode 100644 index 0000000000000000000000000000000000000000..dcf5264187e5142fe7c4f7d957dbd11dbb178e7d --- /dev/null +++ b/day3/examples/geometry/Triangle.hh @@ -0,0 +1,24 @@ +#include "Polygon.hh" +#include <string> +#include <iostream> + +class Triangle : public Polygon<3> { +public: + void sleep(int i, int j=4, int k=9) { + std::cout << i << "\t" << j << "\t" << k << "\n"; + } + void sleeptest() + { + sleep(1); + sleep(9,3,4); + sleep(3,4); + } + Triangle() = default; + Triangle(Point p1, Point p2, Point p3); + Triangle(const Triangle&) = default; + Triangle(Triangle&&) = default; + auto operator=(const Triangle&) -> Triangle& = default; + auto operator=(Triangle &&) -> Triangle& = default; + auto area() const -> double override; + auto name() const -> std::string override { return "Triangle"; } +}; diff --git a/day3/examples/geometry/main.cc b/day3/examples/geometry/main.cc new file mode 100644 index 0000000000000000000000000000000000000000..e83c0b52973f4bda306844388fe89440c6aa3e88 --- /dev/null +++ b/day3/examples/geometry/main.cc @@ -0,0 +1,19 @@ +#include "Circle.hh" +#include "Triangle.hh" +#include <iostream> +#include <memory> +#include <vector> + +auto main() -> int +{ + std::vector<std::unique_ptr<Shape>> shapes; + shapes.push_back(std::make_unique<Circle>(3.0, Point{ 2.3, 4.3 })); + shapes.push_back(std::make_unique<Circle>(2.7, Point{ 0.8, 1.9 })); + shapes.push_back(std::make_unique<Circle>(3.9, Point{ 2.8, 3.6 })); + shapes.push_back(std::make_unique<Triangle>(Point{ 1.8, 2.5 }, Point{ 4.3, 5.4 }, Point{ 2.1, 8.3 })); + for (auto i=0ul; i<shapes.size(); ++i) { + std::cout << i << ": " << shapes[i]->name() + << " with area " << shapes[i]->area() << "\n"; + } +} + diff --git a/day3/examples/ipsum.txt b/day3/examples/ipsum.txt new file mode 100644 index 0000000000000000000000000000000000000000..532d31a7cbdf7eb870f9a634f9055d03e604ddba --- /dev/null +++ b/day3/examples/ipsum.txt @@ -0,0 +1,24 @@ +Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque +laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi +architecto beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas +sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione +voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia dolor sit +amet consectetur adipisci[ng] velit, sed quia non numquam [do] eius modi tempora +inci[di]dunt, ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima +veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid +ex ea commodi consequatur? Quis autem vel eum iure reprehenderit, qui in ea voluptate +velit esse, quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo +voluptas nulla pariatur? + +At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium +voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi sint, +obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt +mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et +expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio, cumque +nihil impedit, quo minus id, quod maxime placeat, facere possimus, omnis voluptas +assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis +debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et +molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut +reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores +repellat ... + diff --git a/day3/examples/lambda_captures.cc b/day3/examples/lambda_captures.cc new file mode 100644 index 0000000000000000000000000000000000000000..2cb21b4124df8a5199425ca61019fd80e661eed8 --- /dev/null +++ b/day3/examples/lambda_captures.cc @@ -0,0 +1,18 @@ +#include "Vbose.hh" + +auto main() -> int +{ + + std::cout << "Declaring lambda function {\n"; + Vbose locvar{ "dinosaur" }; + auto lambda = [=](int i) { + std::cout << "\nIn lambda function, captured value of locvar is : " + << locvar.getval() << "\n"; + return i * i * i; + }; + std::cout << "Declaring lambda function }\n"; + + std::cout << "Calling lambda function {\n"; + std::cout << 5 << " -> " << lambda(5) << "\n"; + std::cout << "Calling lambda function }\n"; +} diff --git a/day3/examples/mutable_lambdas.cc b/day3/examples/mutable_lambdas.cc new file mode 100644 index 0000000000000000000000000000000000000000..95be9dc59bb654b20e05216f417f5dc0d965ca2c --- /dev/null +++ b/day3/examples/mutable_lambdas.cc @@ -0,0 +1,27 @@ +#include <algorithm> +#include <iostream> +#include <vector> +#include <utility> + +int main() +{ + using namespace std; + vector<unsigned long> v, w; + generate_n(back_inserter(v), 100, [i = 0UL]() mutable { + ++i; + return i * i; + }); + // v = [1, 4, 9, 16 ... ] + std::cout << " v = \n"; + for (auto el : v) + std::cout << el << "\n"; + generate_n(back_inserter(w), 50, [ i = 0UL, j = 1UL ]() mutable { + i = std::exchange(j, j + i); + return i; + }); + // w = [1, 1, 2, 3, 5, 8, 11 ...] + + std::cout << " w = \n"; + for (auto el : w) + std::cout << el << "\n"; +} diff --git a/day3/examples/overload_w_concepts.cc b/day3/examples/overload_w_concepts.cc new file mode 100644 index 0000000000000000000000000000000000000000..ab44329122eab83ba248ea1e6eaed4b87ca1a760 --- /dev/null +++ b/day3/examples/overload_w_concepts.cc @@ -0,0 +1,29 @@ +// examples/overload_w_concepts.cc +#include <iostream> +#include <type_traits> +#include <string> +#include <boost/type_index.hpp> + +template <class N> concept Number = std::is_floating_point_v<N> || std::is_integral_v<N>; +template <class N> concept NotNumber = not Number<N>; + +using namespace boost::typeindex; +auto proc(Number auto&& x) -> void +{ + std::cout << "Called proc for numbers with " << x << " of typeid " << type_id_runtime(x) << "\n"; +} +auto proc(NotNumber auto&& x) -> void +{ + std::cout << "Called proc for non-numbers with " << x << " of typeid " << type_id_runtime(x) << "\n"; +} + +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/day3/examples/static_assert0.cc b/day3/examples/static_assert0.cc new file mode 100644 index 0000000000000000000000000000000000000000..fad5884d097b20e2ebe0a0841ac66edad8f6c944 --- /dev/null +++ b/day3/examples/static_assert0.cc @@ -0,0 +1,7 @@ +double advance(unsigned long L) +{ + 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); +} +int main() {} diff --git a/day3/examples/static_assert1.cc b/day3/examples/static_assert1.cc new file mode 100644 index 0000000000000000000000000000000000000000..7c63bb433cab16444ad687c3aa2487e9c36d21a3 --- /dev/null +++ b/day3/examples/static_assert1.cc @@ -0,0 +1,5 @@ +double advance(unsigned long i) +{ + static_assert(sizeof(i) >= 8, "long must be bigger than 8 bytes"); + return 0.; +} diff --git a/day3/examples/static_assert2.cc b/day3/examples/static_assert2.cc new file mode 100644 index 0000000000000000000000000000000000000000..7fa08bacffbb57b8d767740483b4eab0111aa55d --- /dev/null +++ b/day3/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 + } +}; + +int main() +{ + 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/day3/examples/strtrans.cc b/day3/examples/strtrans.cc new file mode 100644 index 0000000000000000000000000000000000000000..5846a3b199cc115ed923f53c52dd358a8d2b0f94 --- /dev/null +++ b/day3/examples/strtrans.cc @@ -0,0 +1,13 @@ +// examples/strtrans.cc +#include <algorithm> +#include <iostream> +#include <string> +auto main() -> int +{ + std::string name; + std::cout << "What's your name ? "; + getline(std::cin, name); + auto bkpname { name }; + std::transform(begin(name), end(name), begin(name), toupper); + std::cout << bkpname << " <--------> " << name << "\n"; +} diff --git a/day3/examples/template_intro.cc b/day3/examples/template_intro.cc new file mode 100644 index 0000000000000000000000000000000000000000..78faceb817316cdeb6818dbddf3ed48482c5b1c2 --- /dev/null +++ b/day3/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"; +}