Skip to content

Instantly share code, notes, and snippets.

@gatchamix
Created October 12, 2018 10:56
Show Gist options
  • Save gatchamix/1f02523631aa5acad412c9a59d6eb1ce to your computer and use it in GitHub Desktop.
Save gatchamix/1f02523631aa5acad412c9a59d6eb1ce to your computer and use it in GitHub Desktop.
additional compile-time replacements for polymorphism (more intrusive for end-user)
#include <type_traits>
//
template <class...>
struct type_pack
{};
//
namespace detail
{
template <class R, class T>
auto constexpr match(R T::*)
-> std::true_type;
template <class...>
auto constexpr match(...)
-> std::false_type;
}
#define has_member_function(...) \
[] \
{ \
using type = __VA_ARGS__; \
HAS_MEMBER_FUNCTION_IMPL_1
#define HAS_MEMBER_FUNCTION_IMPL_1(...) \
auto constexpr helper = [] \
<class __T, class... __Sig> \
(type_pack<__T, __Sig...>) \
-> decltype(detail::match<__Sig...>(&__T::__VA_ARGS__)) \
{}; \
HAS_MEMBER_FUNCTION_IMPL_2
#define HAS_MEMBER_FUNCTION_IMPL_2(...) \
using input = type_pack<type __VA_OPT__(, __VA_ARGS__)>; \
return std::is_invocable_r_v<std::true_type, decltype(helper), input>; \
}()
// check for existance of member functions
//
// usage:
// has_member_function(T[<Ts...>])([template] name[<Us...>])([signature])
// where 'signature' is:
// R([Args...]) [const] [volatile]
//
// CRTP base class
template <class T>
struct foo
{
constexpr foo()
{
// simulated deleted / final virtual function
static_assert(!has_member_function(T)(deleted_function)());
// simulated pure virtual function
static_assert(has_member_function(T)(pure_virtual_function)(bool() const));
}
// simulated virtual function
auto constexpr virtual_function() const
{
if constexpr (has_member_function(T)(virtual_function)(bool() const))
{ return self().virtual_function(); }
else
{ return false; }
}
// calling functions in simulated derived class
auto constexpr downwards_function() const
{ return self().pure_virtual_function(); }
auto constexpr self() const
{ return static_cast<T const&>(*this); }
auto constexpr self()
{ return static_cast<T&>(*this); }
protected:
auto constexpr protected_function() const
{ return virtual_function(); }
};
// CRTP derived class
template <template <class> class T>
struct bar final
: T<bar<T>>
{
using base = T<bar<T>>;
auto constexpr virtual_function() const
{ return true; }
auto constexpr pure_virtual_function() const
{ return true; }
auto constexpr upwards_function() const
{ return base::protected_function(); }
};
//
auto main()
-> int
{
auto constexpr test = bar<foo>{};
static_assert(test.virtual_function());
static_assert(test.pure_virtual_function());
static_assert(test.downwards_function());
static_assert(test.upwards_function());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment