File member_like.h
File List > module > utility > src > scl > utility > type_traits > member_like.h
Go to the documentation of this file
#pragma once
#include <type_traits>
namespace scl::detail
{
template <class Type, class Signature>
struct member_function_like;
enum class member_function_noexcept : bool
{
disabled = false,
enabled = true
};
// Common builder parametrized by Noex (controls noexcept on the member function)
template <class Type, class Result, member_function_noexcept Noexcept, class... Arguments>
struct build_member_function_like
{
private:
static_assert(::std::is_class_v<::std::remove_cvref_t<Type>>,
"member_function_like_t requires Type to be a class type");
using class_t = ::std::remove_cvref_t<Type>;
// All cv/ref forms in one place; noexcept is controlled by Noexcept
using un = Result (class_t::*)(Arguments...);
using c = Result (class_t::*)(Arguments...) const;
using v = Result (class_t::*)(Arguments...) volatile;
using cv = Result (class_t::*)(Arguments...) const volatile;
using un_l = Result (class_t::*)(Arguments...) &;
using un_r = Result (class_t::*)(Arguments...) &&;
using c_l = Result (class_t::*)(Arguments...) const &;
using c_r = Result (class_t::*)(Arguments...) const &&;
using v_l = Result (class_t::*)(Arguments...) volatile &;
using v_r = Result (class_t::*)(Arguments...) volatile &&;
using cv_l = Result (class_t::*)(Arguments...) const volatile &;
using cv_r = Result (class_t::*)(Arguments...) const volatile &&;
static constexpr bool is_c = ::std::is_const_v<::std::remove_reference_t<Type>>;
static constexpr bool is_v = ::std::is_volatile_v<::std::remove_reference_t<Type>>;
static constexpr bool is_l = ::std::is_lvalue_reference_v<Type>;
static constexpr bool is_r = ::std::is_rvalue_reference_v<Type>;
public:
using type = ::std::conditional_t<is_l,
// lvalue-qualified member functions
::std::conditional_t<(is_c && is_v), cv_l, ::std::conditional_t<is_c, c_l, ::std::conditional_t<is_v, v_l, un_l>>>,
::std::conditional_t<is_r,
// rvalue-qualified member functions
::std::conditional_t<(is_c && is_v), cv_r, ::std::conditional_t<is_c, c_r, ::std::conditional_t<is_v, v_r, un_r>>>,
// no ref-qualifier
::std::conditional_t<(is_c && is_v), cv, ::std::conditional_t<is_c, c, ::std::conditional_t<is_v, v, un>>>>>;
};
template <class Type, class Result, class... Arguments>
struct build_member_function_like<Type, Result, member_function_noexcept::enabled, Arguments...>
{
private:
static_assert(::std::is_class_v<::std::remove_cvref_t<Type>>,
"member_function_like_t requires Type to be a class type");
using class_t = ::std::remove_cvref_t<Type>;
// All cv/ref forms in one place; noexcept is controlled by Noexcept
using un = Result (class_t::*)(Arguments...) noexcept;
using c = Result (class_t::*)(Arguments...) const noexcept;
using v = Result (class_t::*)(Arguments...) volatile noexcept;
using cv = Result (class_t::*)(Arguments...) const volatile noexcept;
using un_l = Result (class_t::*)(Arguments...) & noexcept;
using un_r = Result (class_t::*)(Arguments...) && noexcept;
using c_l = Result (class_t::*)(Arguments...) const & noexcept;
using c_r = Result (class_t::*)(Arguments...) const && noexcept;
using v_l = Result (class_t::*)(Arguments...) volatile & noexcept;
using v_r = Result (class_t::*)(Arguments...) volatile && noexcept;
using cv_l = Result (class_t::*)(Arguments...) const volatile & noexcept;
using cv_r = Result (class_t::*)(Arguments...) const volatile && noexcept;
static constexpr bool is_c = ::std::is_const_v<::std::remove_reference_t<Type>>;
static constexpr bool is_v = ::std::is_volatile_v<::std::remove_reference_t<Type>>;
static constexpr bool is_l = ::std::is_lvalue_reference_v<Type>;
static constexpr bool is_r = ::std::is_rvalue_reference_v<Type>;
public:
using type = ::std::conditional_t<is_l,
// lvalue-qualified member functions
::std::conditional_t<(is_c && is_v), cv_l, ::std::conditional_t<is_c, c_l, ::std::conditional_t<is_v, v_l, un_l>>>,
::std::conditional_t<is_r,
// rvalue-qualified member functions
::std::conditional_t<(is_c && is_v), cv_r, ::std::conditional_t<is_c, c_r, ::std::conditional_t<is_v, v_r, un_r>>>,
// no ref-qualifier
::std::conditional_t<(is_c && is_v), cv, ::std::conditional_t<is_c, c, ::std::conditional_t<is_v, v, un>>>>>;
};
// Entry: Signature without noexcept
template <class Type, class Result, class... Arguments>
struct member_function_like<Type, Result(Arguments...)>
: build_member_function_like<Type, Result, member_function_noexcept::disabled, Arguments...>
{};
// Entry: Signature with noexcept
template <class Type, class Result, class... Arguments>
struct member_function_like<Type, Result(Arguments...) noexcept>
: build_member_function_like<Type, Result, member_function_noexcept::enabled, Arguments...>
{};
// Fallback for non-function Signature
template <class Type, class Signature>
struct member_function_like
{
static_assert(::std::is_function_v<Signature>,
"::scl::member_function_like_t requires a function type like Result(Arguments...) or Result(Arguments...) noexcept");
};
template <class Type, class Member>
struct member_property_like
{
private:
using class_t = ::std::remove_cvref_t<Type>;
static_assert(::std::is_class_v<class_t> || ::std::is_union_v<class_t>,
"member_property_like_t requires Type to be a class or union type");
static_assert(!::std::is_function_v<Member>,
"member_property_like_t expects a data member type; use member_function_like_t for member functions");
using no_ref_t = ::std::remove_reference_t<Type>;
using member_like_c_t =
::std::conditional_t<::std::is_const_v<no_ref_t>, ::std::add_const_t<Member>, Member>;
using member_like_cv_t =
::std::conditional_t<::std::is_volatile_v<no_ref_t>, ::std::add_volatile_t<member_like_c_t>, member_like_c_t>;
public:
using type = member_like_cv_t(class_t::*);
};
template <class Type, class T, bool IsFunction = ::std::is_function_v<T>>
struct member_like;
template <class Type, class Signature>
struct member_like<Type, Signature, true> : member_function_like<Type, Signature>
{};
template <class Type, class Member>
struct member_like<Type, Member, false> : member_property_like<Type, Member>
{};
} // namespace scl::detail
namespace scl
{
template <class Type, class Signature>
using member_function_like_t = typename ::scl::detail::member_function_like<Type, Signature>::type;
template <class Type, class Member>
using member_property_like_t = typename ::scl::detail::member_property_like<Type, Member>::type;
template <class Type, class Member>
using member_like_t = typename ::scl::detail::member_like<Type, Member>::type;
} // namespace scl