@Andy Nguyen , anything we can improve there?Alright, I found the detailed syllabus by clicking on something which at first just looked like graphics and not a button.
One way is to describe a course at two levels.
Hi,Alright, I found the detailed syllabus by clicking on something which at first just looked like graphics and not a button.
Worlk work, work.To be honest, I did not dare to send a following email with further questions after receiving replies to the first one I sent.
The reason is that they replied late at night, which means (I guess) that they are very busy.
I use flow charts for something else than a design sketch.FLOW CHARTS
are useful techniques to sketch the design of a program before coding in C and C++
Flowchart - Wikipedia
en.wikipedia.org
// DJD 2022-10-9 version 0.9 #6
// (C) Datasim Education BV 2022
/*
A really modern implementation of a generic Visitor pattern that is an improvement on other approaches in C++:
1. std::visit() and std::variant()
2. Traditional Acyclic Visitor using subtype polymorphism, dynamic casting and
possibly multiple inheritance.
The proposed solution is more maintainable than solutions 1 and 2 while at the same time having better performance and reliability properties than solution 2. Our solution uses a combination of
template methods and C++ Concepts.
We take the well-known example of 2d shapes (Point, Line, Circle) that can be visited in different ways.
The two visitors represent new functionality for drawing and scaling these shapes.
We note that we do not have a class hierarchy nor virtual functions. All behaviour is compile-time driven as it were.
C++ Concepts is a game changer.
This code contains:
1. Visitor pattern based on C++20 Concepts (provide-requires contracts).
2. Multimethods (the Holy Grail) .. what C++ tried for 30 years.
3. Multimethods with variadic parameters, a) object with multiple visitors,
b) a visitor with multiple objects.
WE GIVE A STRIPPED DOWN VERSION TO FIT ON PAGE
More later.
*/
#include <iostream>
// Visitor with templates,V2
struct Point;
// Using C++20 Concepts to define contracts/protocols
// 1. The baseline contract between GOF Context and Visitor
template <typename Visitor, typename Context>
concept IVisitor = requires (Visitor & v, Context & c)
{
v.visit(c);
};
template <typename Visitor, typename Context>
concept IAccept = requires (Visitor & v, Context & c)
{
c.accept(v);
};
template <typename Visitor, typename Context>
concept IAcceptVisitor = IVisitor<Visitor, Context> && IAccept<Visitor, Context>;
// Specialisations of Concept interfaces (from 2 to 1 template parameter)
template <typename Visitor>
concept IPointVisitor = IVisitor<Visitor, Point>;
/* End of Protocol definitions*/
struct Point
{
double x;
double y;
Point() : x(0.0), y(0.0) {}
Point(double X, double Y) : x(X), y(Y) {}
template <typename T> requires IPointVisitor<T>
void accept(T& t)
{
t.visit(*this);
}
};
// Specific visitors (Draw and Scale)
struct Draw
{
void visit(Point& p)
{
std::cout << "("<< p.x << ", " << p.y << ")\n";
}
};
struct Scale
{
double fac;
Scale(double factor) : fac(factor) {}
void visit(Point& p)
{
p.x *= fac;
p.y *= fac;
}
};
// Multimethods, the Holy Grail of C++
template <typename Visitor, typename Context>
void multimethod(Visitor& v, Context& c) requires IAcceptVisitor<Visitor, Context>
{
v.visit(c);
c.accept(v);
}
// Command multipattern ... a list of objects on a single visitor
template <typename T, typename Visitor>
void command(Visitor v, T& c)
{
c.accept(v);
}
template <typename T, typename Visitor, typename ... Types>
void command(Visitor v , T& arg, Types& ... args)
{ // 1 visitor, multiple contexts
command(v, arg);
command(v, args...);
}
// Command multipattern ... a list of visitors on a single object
template <typename T, typename Visitor>
void command2(T& c, Visitor v)
{
// c.accept(v);
v.visit(c);
}
template <typename T, typename Visitor, typename ... Types>
void command2(T& arg, Visitor& v, Types& ... args)
{ // 1 context, multiple visitors
command2(arg, v);
command2(arg, args...);
}
int main()
{
// Contract with C++ 20 Concepts
{
std::cout << "Contracts, points and lines\n";
Point p1(2.0, -3.0);
Draw draw;
Scale mod(0.5);
p1.accept(mod);
p1.accept(draw);
mod.visit(p1);
draw.visit(p1);
p1.accept(mod);
draw.visit(p1);
}
{
// multimethods
std::cout << "Multimethod\n";
Point p(2.0, 4.0); Point p2(20.0, 41.0);
Point p3(-2.0, -4.0); Point p4(21.0, 42.0);
Draw draw;
Scale mod(0.5);
// Magic
multimethod(draw, p);
multimethod(mod, p);
multimethod(draw, p);
std::cout << "variadics\n";
command(draw, p);
// Multimethods with variadic parameters
command(draw, p, p2, p3, p4);
// Object with multiple visitors
command2(p, draw, mod, draw, mod, draw, mod, draw);
command2(p2, draw, mod, draw);
}
}
This is really good stuff - thank you for sharing.C++:// DJD 2022-10-9 version 0.9 #6 // (C) Datasim Education BV 2022 /* A really modern implementation of a generic Visitor pattern that is an improvement on other approaches in C++: 1. std::visit() and std::variant() 2. Traditional Acyclic Visitor using subtype polymorphism, dynamic casting and possibly multiple inheritance. The proposed solution is more maintainable than solutions 1 and 2 while at the same time having better performance and reliability properties than solution 2. Our solution uses a combination of template methods and C++ Concepts. We take the well-known example of 2d shapes (Point, Line, Circle) that can be visited in different ways. The two visitors represent new functionality for drawing and scaling these shapes. We note that we do not have a class hierarchy nor virtual functions. All behaviour is compile-time driven as it were. C++ Concepts is a game changer. This code contains: 1. Visitor pattern based on C++20 Concepts (provide-requires contracts). 2. Multimethods (the Holy Grail) .. what C++ tried for 30 years. 3. Multimethods with variadic parameters, a) object with multiple visitors, b) a visitor with multiple objects. WE GIVE A STRIPPED DOWN VERSION TO FIT ON PAGE More later. */ #include <iostream> // Visitor with templates,V2 struct Point; // Using C++20 Concepts to define contracts/protocols // 1. The baseline contract between GOF Context and Visitor template <typename Visitor, typename Context> concept IVisitor = requires (Visitor & v, Context & c) { v.visit(c); }; template <typename Visitor, typename Context> concept IAccept = requires (Visitor & v, Context & c) { c.accept(v); }; template <typename Visitor, typename Context> concept IAcceptVisitor = IVisitor<Visitor, Context> && IAccept<Visitor, Context>; // Specialisations of Concept interfaces (from 2 to 1 template parameter) template <typename Visitor> concept IPointVisitor = IVisitor<Visitor, Point>; /* End of Protocol definitions*/ struct Point { double x; double y; Point() : x(0.0), y(0.0) {} Point(double X, double Y) : x(X), y(Y) {} template <typename T> requires IPointVisitor<T> void accept(T& t) { t.visit(*this); } }; // Specific visitors (Draw and Scale) struct Draw { void visit(Point& p) { std::cout << "("<< p.x << ", " << p.y << ")\n"; } }; struct Scale { double fac; Scale(double factor) : fac(factor) {} void visit(Point& p) { p.x *= fac; p.y *= fac; } }; // Multimethods, the Holy Grail of C++ template <typename Visitor, typename Context> void multimethod(Visitor& v, Context& c) requires IAcceptVisitor<Visitor, Context> { v.visit(c); c.accept(v); } // Command multipattern ... a list of objects on a single visitor template <typename T, typename Visitor> void command(Visitor v, T& c) { c.accept(v); } template <typename T, typename Visitor, typename ... Types> void command(Visitor v , T& arg, Types& ... args) { // 1 visitor, multiple contexts command(v, arg); command(v, args...); } // Command multipattern ... a list of visitors on a single object template <typename T, typename Visitor> void command2(T& c, Visitor v) { // c.accept(v); v.visit(c); } template <typename T, typename Visitor, typename ... Types> void command2(T& arg, Visitor& v, Types& ... args) { // 1 context, multiple visitors command2(arg, v); command2(arg, args...); } int main() { // Contract with C++ 20 Concepts { std::cout << "Contracts, points and lines\n"; Point p1(2.0, -3.0); Draw draw; Scale mod(0.5); p1.accept(mod); p1.accept(draw); mod.visit(p1); draw.visit(p1); p1.accept(mod); draw.visit(p1); } { // multimethods std::cout << "Multimethod\n"; Point p(2.0, 4.0); Point p2(20.0, 41.0); Point p3(-2.0, -4.0); Point p4(21.0, 42.0); Draw draw; Scale mod(0.5); // Magic multimethod(draw, p); multimethod(mod, p); multimethod(draw, p); std::cout << "variadics\n"; command(draw, p); // Multimethods with variadic parameters command(draw, p, p2, p3, p4); // Object with multiple visitors command2(p, draw, mod, draw, mod, draw, mod, draw); command2(p2, draw, mod, draw); } }
Hi Devon,This is really good stuff - thank you for sharing.
The GOF pattern is long overdue to be revamped, so I'm really excited to learn more on your research and thoughts.Hi Devon,
And there's more ... I am resuccitating the GOF Pattern intp C++20 style.
I'll keep posting here.
C++20 Concepts really tax my brain. Why? 7 plus or minus 2.
The Magical Number Seven, Plus or Minus Two - Wikipedia
en.wikipedia.org