Last active
October 15, 2022 16:45
-
-
Save Konard/20e36d44c9b6aa7c390470928a1d8ebb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <tuple> | |
#include <functional> | |
#define THIS_REFERENCE_WRAPPER_METHODS(MethodName, TWrapped) \ | |
constexpr auto&& MethodName() & { return static_cast<TWrapped&>(*this); } \ | |
constexpr auto&& MethodName() && { return static_cast<TWrapped&&>(*this); } \ | |
constexpr auto&& MethodName() const & { return static_cast<const TWrapped&>(*this); } \ | |
constexpr auto&& MethodName() const && { return static_cast<const TWrapped&&>(*this); } | |
#define VARIABLE_WRAPPER_METHODS(MethodName, VariableName) \ | |
constexpr auto&& MethodName() & { return VariableName; } \ | |
constexpr auto&& MethodName() && { return VariableName; } \ | |
constexpr auto&& MethodName() const & { return VariableName; } \ | |
constexpr auto&& MethodName() const && { return VariableName; } | |
#define EXTENDED_BASE_TYPE(TExtended, TExtendedBase, TExtendable, TFirstExtender, TExtenders) \ | |
TFirstExtender< \ | |
std::conditional_t< \ | |
sizeof...(TExtenders) >= 2, \ | |
TExtended<TExtendable, TExtenders...>, \ | |
std::tuple_element_t< \ | |
0, \ | |
std::tuple<TExtenders<TExtendedBase<TExtendable>>...> \ | |
> \ | |
> \ | |
> | |
#define DECORATED_BASE_TYPE(TDecoratedBase, TFacade, TDecorated, TFirstDecorator, TDecorators)\ | |
TFirstDecorator< \ | |
TFacade, \ | |
std::conditional_t< \ | |
sizeof...(TDecorators) >= 2, \ | |
TDecoratedBase<TFacade, TDecorated, TDecorators...>, \ | |
std::tuple_element_t< \ | |
0, \ | |
std::tuple<TDecorators<TFacade, TDecorated>...> \ | |
> \ | |
> \ | |
> | |
#define USE_ALL_BASE_CONSTRUCTORS(TSelf, TBase) \ | |
template <typename ...TParams> \ | |
TSelf(TParams&&... params) : TBase(std::forward<TParams>(params)...) {} | |
template<typename TSelf, typename ...TBase> | |
class Polymorph : public TBase... | |
{ | |
protected: | |
THIS_REFERENCE_WRAPPER_METHODS(object, TSelf) | |
}; | |
template<typename TExtendable> | |
class ExtendedBase : public TExtendable | |
{ | |
public: | |
THIS_REFERENCE_WRAPPER_METHODS(extended, TExtendable) | |
}; | |
template<typename TExtendable, template<typename> typename TFirstExtender, template<typename> typename ...TExtenders> | |
class Extended : public EXTENDED_BASE_TYPE(Extended, ExtendedBase, TExtendable, TFirstExtender, TExtenders) | |
{ | |
}; | |
template<typename TExtendable> | |
class ExtendedReferenceBase | |
{ | |
public: | |
ExtendedReferenceBase(TExtendable& reference) : extendable(reference) { } | |
VARIABLE_WRAPPER_METHODS(extended, extendable) | |
protected: | |
TExtendable& extendable; | |
}; | |
template<typename TExtendable, template<typename> typename TFirstExtender, template<typename> typename ...TExtenders> | |
class ExtendedReference : public EXTENDED_BASE_TYPE(ExtendedReference, ExtendedReferenceBase, TExtendable, TFirstExtender, TExtenders) | |
{ | |
using base = EXTENDED_BASE_TYPE(ExtendedReference, ExtendedReferenceBase, TExtendable, TFirstExtender, TExtenders); | |
public: | |
USE_ALL_BASE_CONSTRUCTORS(ExtendedReference, base) | |
}; | |
template<typename TExtendable> | |
class ExtendedContainerBase | |
{ | |
public: | |
VARIABLE_WRAPPER_METHODS(extended, extendable) | |
protected: | |
TExtendable extendable; | |
}; | |
template<typename TExtendable, template<typename> typename TFirstExtender, template<typename> typename ...TExtenders> | |
class ExtendedContainer : public EXTENDED_BASE_TYPE(ExtendedContainer, ExtendedContainerBase, TExtendable, TFirstExtender, TExtenders) | |
{ | |
}; | |
template<typename TFacade, typename TDecorated> | |
struct DecoratorBase : public TDecorated | |
{ | |
USE_ALL_BASE_CONSTRUCTORS(DecoratorBase, TDecorated) | |
THIS_REFERENCE_WRAPPER_METHODS(decorated, TDecorated) | |
THIS_REFERENCE_WRAPPER_METHODS(facade, TDecorated) | |
}; | |
template<typename TFacade, typename TDecorated, template<typename, typename> typename TFirstDecorator, template<typename, typename> typename ...TDecorators> | |
struct DecoratedBase : public DECORATED_BASE_TYPE(DecoratedBase, TFacade, TDecorated, TFirstDecorator, TDecorators) | |
{ | |
using base = DECORATED_BASE_TYPE(DecoratedBase, TFacade, TDecorated, TFirstDecorator, TDecorators); | |
USE_ALL_BASE_CONSTRUCTORS(DecoratedBase, base) | |
}; | |
template<typename TDecorated, template<typename, typename> typename TFirstDecorator, template<typename, typename> typename ...TDecorators> | |
struct Decorated : public DecoratedBase<Decorated<TDecorated, TFirstDecorator, TDecorators...>, TDecorated, TFirstDecorator, TDecorators...> | |
{ | |
using base = DecoratedBase<Decorated<TDecorated, TFirstDecorator, TDecorators...>, TDecorated, TFirstDecorator, TDecorators...>; | |
USE_ALL_BASE_CONSTRUCTORS(Decorated, base) | |
}; | |
template <typename TSelf, typename TValue, typename... TArgument> | |
concept CSetter = sizeof...(TArgument) <= 1 && | |
requires(TSelf self, TArgument... argument, TValue value) | |
{ | |
{ self.Set(argument..., value) } -> std::same_as<void>; | |
}; | |
template <typename ...> class ISetter; | |
template <typename TValue, typename TArgument> class ISetter<TValue, TArgument> | |
{ | |
public: | |
virtual void Set(TArgument argument, TValue value) = 0; | |
}; | |
template <typename TValue> class ISetter<TValue> | |
{ | |
public: | |
virtual void Set(TValue value) = 0; | |
}; | |
// Class inheritable via static polymorphism | |
template<typename TValue, typename TSelf, typename ...TBase> | |
class SetterBase : public Polymorph<TSelf, TBase...> | |
{ | |
using base = Polymorph<TSelf, TBase...>; | |
public: | |
void Set(TValue value) | |
{ | |
std::cout << "base: " << value << std::endl; | |
this->object().Set(value); | |
} | |
void Reset(TValue value) | |
{ | |
this->object().Set(value); | |
} | |
}; | |
// Class that is non-inheritable via static polymorphism | |
// It is "sealed/final" in static polymorphism hierarchy, | |
// but it is still available for inheritance in dynamic polymorphism hierarchy. | |
template<typename TValue, typename ...TBase> | |
class Setter : public SetterBase<TValue, Setter<TValue, TBase...>, TBase...> | |
{ | |
using base = SetterBase<TValue, Setter<TValue, TBase...>, TBase...>; | |
public: | |
std::function<void(TValue)> Set = [this](TValue value) | |
{ | |
std::cout << "derived: " << value << std::endl; | |
}; | |
}; | |
template<typename TValue, CSetter<TValue> TBase> | |
class SetterDecoratorViaInheritance : public TBase | |
{ | |
using base = TBase; | |
public: | |
void Set(TValue value) | |
{ | |
std::cout << "decorated via inheritance: " << value << std::endl; | |
base::Set(value); | |
} | |
}; | |
template<typename TValue, CSetter<TValue> TBase> | |
class SetterDecoratorViaComposition | |
{ | |
using base = TBase; | |
base baseInstance; | |
public: | |
void Set(TValue value) | |
{ | |
std::cout << "decorated via composition: " << value << std::endl; | |
baseInstance.Set(value); | |
} | |
}; | |
template<typename TValue, CSetter<TValue> TBase = ISetter<TValue>> | |
class SetterDecoratorViaReference | |
{ | |
TBase& baseInstance; | |
public: | |
SetterDecoratorViaReference(TBase& setter) : baseInstance(setter) { } | |
void Set(TValue value) | |
{ | |
std::cout << "decorated: " << value << std::endl; | |
baseInstance.Set(value); | |
} | |
}; | |
template<typename TExtendable> | |
class Extension1 : public TExtendable | |
{ | |
public: | |
USE_ALL_BASE_CONSTRUCTORS(Extension1, TExtendable) | |
void SetIt1(std::string value) | |
{ | |
this->extended().Set(value); | |
} | |
}; | |
template<typename TFacade, typename TDecorated> | |
class Decorator1 : public DecoratorBase<TFacade, TDecorated> | |
{ | |
using base = DecoratorBase<TFacade, TDecorated>; | |
public: | |
USE_ALL_BASE_CONSTRUCTORS(Decorator1, base) | |
void SetIt1(std::string value) | |
{ | |
this->decorated().Set(value); | |
} | |
void SetViaFacade1(std::string value) | |
{ | |
this->facade().Set(value); | |
} | |
}; | |
template<typename TExtendable> | |
class Extension2 : public TExtendable | |
{ | |
public: | |
USE_ALL_BASE_CONSTRUCTORS(Extension2, TExtendable) | |
void SetIt2(std::string value) | |
{ | |
this->extended().Set(value); | |
} | |
}; | |
template<typename TFacade, typename TDecorated> | |
class Decorator2 : public DecoratorBase<TFacade, TDecorated> | |
{ | |
using base = DecoratorBase<TFacade, TDecorated>; | |
public: | |
USE_ALL_BASE_CONSTRUCTORS(Decorator2, base) | |
void SetIt2(std::string value) | |
{ | |
this->decorated().Set(value); | |
} | |
void SetViaFacade2(std::string value) | |
{ | |
this->facade().Set(value); | |
} | |
}; | |
template<typename TExtendable> | |
class Extension3 : public TExtendable | |
{ | |
public: | |
USE_ALL_BASE_CONSTRUCTORS(Extension3, TExtendable) | |
void SetIt3(std::string value) | |
{ | |
this->extended().Set(value); | |
} | |
}; | |
template<typename TFacade, typename TDecorated> | |
class Decorator3 : public DecoratorBase<TFacade, TDecorated> | |
{ | |
using base = DecoratorBase<TFacade, TDecorated>; | |
public: | |
USE_ALL_BASE_CONSTRUCTORS(Decorator3, base) | |
void SetIt3(std::string value) | |
{ | |
this->decorated().Set(value); | |
} | |
void SetViaFacade3(std::string value) | |
{ | |
this->facade().Set(value); | |
} | |
}; | |
template<typename TExtendable> | |
class Extension4 : public TExtendable | |
{ | |
public: | |
USE_ALL_BASE_CONSTRUCTORS(Extension4, TExtendable) | |
void SetIt4(std::string value) | |
{ | |
this->extended().Set(value); | |
} | |
}; | |
void dynamic_polymorphism() | |
{ | |
using DynamicSetterType = Setter<std::string, ISetter<std::string>>; | |
DynamicSetterType ds; | |
ds.Set("call via dynamic setter"); | |
std::cout << std::endl; | |
ISetter<std::string>& is = ds; | |
is.Set("call from interface"); | |
SetterDecoratorViaInheritance<std::string, DynamicSetterType> dsi; | |
dsi.Set("set"); | |
std::cout << std::endl; | |
SetterDecoratorViaComposition<std::string, DynamicSetterType> dsc; | |
dsc.Set("set"); | |
std::cout << std::endl; | |
// Concrete Reference | |
SetterDecoratorViaReference<std::string, DynamicSetterType> dsr(ds); | |
dsr.Set("set"); | |
// Abstract Reference | |
std::cout << std::endl; | |
SetterDecoratorViaReference<std::string> dsir(ds); | |
dsir.Set("dsir.Set"); | |
} | |
void static_polymorphism() | |
{ | |
using StaticSetterType = Setter<std::string>; | |
StaticSetterType ss; | |
ss.Set("ss.Set"); | |
ss.Reset("ss.Reset"); | |
std::cout << std::endl; | |
SetterDecoratorViaInheritance<std::string, StaticSetterType> ssi; | |
ssi.Set("ssi.Set"); | |
std::cout << std::endl; | |
SetterDecoratorViaComposition<std::string, StaticSetterType> ssc; | |
ssc.Set("ssc.Set"); | |
std::cout << std::endl; | |
// Concrete Reference | |
SetterDecoratorViaReference<std::string, StaticSetterType> ssr(ss); | |
ssr.Set("ssr.Set"); | |
} | |
void hybrid_polymorphism() | |
{ | |
Setter<std::string> staticSetter; | |
staticSetter.Set("staticSetter.Set"); | |
Setter<std::string, ISetter<std::string>> dynamicSetter; | |
dynamicSetter.Set("dynamicSetter.Set"); | |
Extended<Setter<std::string, ISetter<std::string>>, Extension1, Extension2, Extension3, Extension4> extendedSetter; | |
extendedSetter.Set("extendedSetter.Set"); | |
extendedSetter.extended().Set("extendedSetter.ExtendedInstance().Set"); | |
extendedSetter.SetIt1("extendedSetter.SetIt1"); | |
extendedSetter.SetIt2("extendedSetter.SetIt2"); | |
extendedSetter.SetIt3("extendedSetter.SetIt3"); | |
extendedSetter.SetIt4("extendedSetter.SetIt4"); | |
ExtendedReference<Setter<std::string, ISetter<std::string>>, Extension1, Extension2, Extension3, Extension4> extendedSetterReference(dynamicSetter); | |
extendedSetterReference.extended().Set("extendedSetterReference.ExtendedInstance().Set"); | |
extendedSetterReference.SetIt1("extendedSetterReference.SetIt1"); | |
extendedSetterReference.SetIt2("extendedSetterReference.SetIt2"); | |
extendedSetterReference.SetIt3("extendedSetterReference.SetIt3"); | |
extendedSetterReference.SetIt4("extendedSetterReference.SetIt4"); | |
ExtendedContainer<Setter<std::string, ISetter<std::string>>, Extension1, Extension2, Extension3, Extension4> extendedSetterContainer; | |
extendedSetterContainer.extended().Set("extendedSetterContainer.ExtendedInstance().Set"); | |
extendedSetterContainer.SetIt1("extendedSetterContainer.SetIt1"); | |
extendedSetterContainer.SetIt2("extendedSetterContainer.SetIt2"); | |
extendedSetterContainer.SetIt3("extendedSetterContainer.SetIt3"); | |
extendedSetterContainer.SetIt4("extendedSetterContainer.SetIt4"); | |
} | |
void facade_polymorphism() | |
{ | |
Setter<std::string> staticSetter; | |
staticSetter.Set("staticSetter.Set"); | |
Setter<std::string, ISetter<std::string>> dynamicSetter; | |
dynamicSetter.Set("dynamicSetter.Set"); | |
Decorated<Setter<std::string, ISetter<std::string>>, Decorator1, Decorator2> facadedSetter1; | |
facadedSetter1.Set("facadedSetter1.Set"); | |
facadedSetter1.decorated().Set("facadedSetter1.decorated().Set"); | |
facadedSetter1.SetIt1("facadedSetter1.SetIt1"); | |
facadedSetter1.SetViaFacade1("facadedSetter1.SetViaFacade1"); | |
facadedSetter1.SetIt2("facadedSetter1.SetIt2"); | |
facadedSetter1.SetViaFacade2("facadedSetter1.SetViaFacade2"); | |
Decorated<Setter<std::string, ISetter<std::string>>, Decorator1, Decorator2, Decorator3> facadedSetter2; | |
facadedSetter2.Set("facadedSetter2.Set"); | |
facadedSetter2.decorated().Set("facadedSetter2.decorated().Set"); | |
facadedSetter2.SetIt1("facadedSetter2.SetIt1"); | |
facadedSetter2.SetViaFacade1("facadedSetter2.SetViaFacade1"); | |
facadedSetter2.SetIt2("facadedSetter2.SetIt2"); | |
facadedSetter2.SetViaFacade2("facadedSetter2.SetViaFacade2"); | |
facadedSetter2.SetIt3("facadedSetter2.SetIt3"); | |
facadedSetter2.SetViaFacade3("facadedSetter2.SetViaFacade3"); | |
} | |
int main() | |
{ | |
dynamic_polymorphism(); | |
static_polymorphism(); | |
hybrid_polymorphism(); | |
facade_polymorphism(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment