// https://wandbox.org/permlink/udzltQne483qGrat
// dbj@dbj.org from popular C++17 youtube examples
#include <iostream>
#include <variant>
#include <vector>
// vararg inheritance and overloading of thus inherited
// 'Functor' is a type that has public function call operator
// arguments are vararg of Functor types
template<typename ... Functors>
// inherit from var num of Functor types passed as
// template arguments above
struct Ovld : Functors ... {
// have here function call operators from all the Functors inherited
// derive a call operator from all functors
using Functors::operator() ... ;
};
// user defined deduction guide
template<typename...Functors> Ovld(Functors...) /*seeing this ctor */
-> /* induce */
Ovld<Functors...> ; /* this as being it's type */
// we do not have to use the above mechanism
// but we are not sure design principles
// behind are not superior?
#define USE_OVERLORD
Funny enough we have this elaborate hierachy generator, but we do not like polymorphism.
Instead we could have opted for this C++17 mechanisms bellow, to achieve (with no hacks) polymorphism with no inheritance. By using std::variant
. And not using the Ovld
.
// https://youtu.be/e2ZQyYr0Oi0
// shapes with no common ancestor
struct Circle {
void draw () { std::cout << "\n drawing Circle" ; }
};
struct Line {
void draw () { std::cout << "\n drawing Line" ; }
};
// basically std::variant is allowing us to
// have one type for the std::vector
// used latter
using GeoObj = std::variant<Circle, Line> ;
// visit each GeoObj and call `draw()` on it
inline void drawer ( std::vector<GeoObj> shapes )
{
for ( auto && geoobj : shapes )
{
#if ! defined(USE_OVERLORD)
// this stays unchanged if we add 'Triangle'
std::visit( [] ( auto && obj ) { obj.draw(); }, geoobj ) ;
#else
std::visit(
// not created before here
Ovld{
// give two functors as two lambdas to the ctor of Ovld
// caller needs to explicitly code for each shape here
[] (Circle & c){ c.draw(); },
[] (Line & l){ l.draw(); }
},
geoobj );
#endif
}
}
int main()
{
std::vector<GeoObj> shapes{ Circle{}, Line{} };
drawer( shapes );
std::cout << "\n\nDONE!" << std::endl;
}
Ovld
is C++17, that also seems very complex to majority of C++ programmers. And certianly to all non C++ programmers.
But, it only generates a simple hierarchical structure ot Types given as Ovld
template parameters. Each of them programers would probably understand this diagram immediately.
Ovld working with std::variant
dispatches the draw
message based on the type.
Instance of the Ovld
is the visitor to the variant.
So, we have this advanced C++17 features, working together that generate this one simple type hierachy, and overloads functioning inside. Written in a very condensed code, that is hard to understand.
What are the prevailing benefits of the concepts on top of which Ovld
is coded?
The key benefit is polymorphism with no inheritance.
Triangle
.As in the quantum phenomena: It depends on the oobserver.