Skip to content

Instantly share code, notes, and snippets.

@Konard
Last active October 15, 2022 16:45
Show Gist options
  • Save Konard/20e36d44c9b6aa7c390470928a1d8ebb to your computer and use it in GitHub Desktop.
Save Konard/20e36d44c9b6aa7c390470928a1d8ebb to your computer and use it in GitHub Desktop.
#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