#include #include #include #include using namespace std; #include #include struct Shape { virtual string str() const = 0; }; struct Circle : Shape { float radius; Circle(){} explicit Circle(const float radius) : radius{radius} { } void resize(float factor) { radius *= factor; } string str() const override { ostringstream oss; oss << "A circle of radius " << radius; return oss.str(); } }; struct Square : Shape { float side; Square(){} explicit Square(const float side) : side{side} { } string str() const override { ostringstream oss; oss << "A square of with side " << side; return oss.str(); } }; // we are not changing the base class of existing // objects // cannot make, e.g., ColoredSquare, ColoredCircle, etc. struct ColoredShape : Shape { Shape& shape; string color; ColoredShape(Shape& shape, const string& color) : shape{shape}, color{color} { } string str() const override { ostringstream oss; oss << shape.str() << " has the color " << color; return oss.str(); } }; struct TransparentShape : Shape { Shape& shape; uint8_t transparency; TransparentShape(Shape& shape, const uint8_t transparency) : shape{shape}, transparency{transparency} { } string str() const override { ostringstream oss; oss << shape.str() << " has " << static_cast(transparency) / 255.f*100.f << "% transparency"; return oss.str(); } }; // mixin inheritance // note: class, not typename template struct ColoredShape2 : T { static_assert(is_base_of::value, "Template argument must be a Shape"); string color; // need this (or not!) ColoredShape2(){} template ColoredShape2(const string& color, Args ...args) : T(std::forward(args)...), color{color} // you cannot call base class ctor here // b/c you have no idea what it is { } string str() const override { ostringstream oss; oss << T::str() << " has the color " << color; return oss.str(); } }; template struct TransparentShape2 : T { uint8_t transparency; template TransparentShape2(const uint8_t transparency, Args ...args) : T(std::forward(args)...), transparency{ transparency } { } string str() const override { ostringstream oss; oss << T::str() << " has " << static_cast(transparency) / 255.f * 100.f << "% transparency"; return oss.str(); } }; void wrapper() { Circle circle{ 5 }; cout << circle.str() << endl; ColoredShape red_circle{ circle, "red" }; cout << red_circle.str() << endl; //red_circle.resize(); // oops TransparentShape red_half_visible_circle{ red_circle, 128 }; cout << red_half_visible_circle.str() << endl; } void mixin_inheritance() { // won't work without a default constructor ColoredShape2 green_circle{ "green" }; green_circle.radius = 123; cout << green_circle.str() << endl; TransparentShape2> blue_invisible_square{ 0 }; blue_invisible_square.color = "blue"; blue_invisible_square.side = 321; cout << blue_invisible_square.str() << endl; } struct Logger { function func; string name; Logger(const function& func, const string& name) : func{func}, name{name} { } void operator()() const { cout << "Entering " << name << endl; func(); cout << "Exiting " << name << endl; } }; template struct Logger2 { Func func; string name; Logger2(const Func& func, const string& name) : func{func}, name{name} { } void operator()() const { cout << "Entering " << name << endl; func(); cout << "Exiting " << name << endl; } }; template auto make_logger2(Func func, const string& name) { return Logger2{ func, name }; } // need partial specialization for this to work template struct Logger3; // return type and argument list template struct Logger3 { Logger3(function func, const string& name) : func{func}, name{name} { } R operator() (Args ...args) { cout << "Entering " << name << endl; R result = func(args...); cout << "Exiting " << name << endl; return result; } function func; string name; }; template auto make_logger3(R (*func)(Args...), const string& name) { return Logger3( std::function(func), name); } double add(double a, double b) { cout << a << "+" << b << "=" << (a + b) << endl; return a + b; } void function_decorator() { //Logger([]() {cout << "Hello" << endl; }, "HelloFunction")(); // cannot do this //make_logger2([]() {cout << "Hello" << endl; }, "HelloFunction")(); auto call = make_logger2([]() {cout << "Hello!" << endl; }, "HelloFunction"); call(); auto logged_add = make_logger3(add, "Add"); auto result = logged_add(2, 3); } void constructor_forwarding() { struct NotAShape { virtual string str() const { return string{}; } }; // we don't want this to be legal, thus a static_assert above //ColoredShape2 legal; // no code completion for this case // can comment out argument, too! (default constructor) TransparentShape2 hidden_square{ 1, 2 }; cout << hidden_square.str() << endl; ColoredShape2> sq = { "red", 51, 5 }; cout << sq.str() << endl; } int main() { function_decorator(); //wrapper(); //mixin_inheritance(); //constructor_forwarding(); getchar(); return 0; }