basedOpinionated utility library |
git clone git://git.dimitrijedobrota.com/based.git |
Log | Files | Refs | README | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING | |
commit | 7d46d516559e7bca2d59ae72ae66b04918ad9fd0 |
parent | 131c6b5b0cf82b745d34986c31e8bf6cd519e685 |
author | Dimitrije Dobrota <mail@dimitrijedobrota.com> |
date | Tue, 25 Mar 2025 14:54:11 +0100 |
Domain and Codomain don't rely on magic anymore
Diffstat:M | example/type_traits.cpp | | | ++++++++++++++++++++++++++++++++++++------------------------ |
M | include/based/type_traits.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------- |
2 files changed, 126 insertions(+), 53 deletions(-)
diff --git a/example/type_traits.cpp b/example/type_traits.cpp
@@ -16,40 +16,52 @@ struct irregular
template<typename T>
struct identity
{
using input_types = std::tuple<T>;
using output_type = T;
output_type operator()(T val) { return val; }
T operator()(T val) { return val; }
};
struct identity_wrong_input_tuple
template<typename T, typename U>
struct add
{
using input_types = int; // should be a tuple
using output_type = int;
output_type operator()(int val) { return val; }
T operator()(T val1, U val2) { return val1 + val2; }
};
struct identity_wrong_input_tuple_irregular
int main()
{
using input_types = std::tuple<irregular>; // should be a regular tuple
using output_type = int;
using id = identity<double>;
using ii = identity<irregular>;
output_type operator()(irregular /* val */) { return 1; }
};
static_assert(std::same_as<based::domain_t<id>, std::tuple<double>>);
static_assert(std::same_as<based::codomain_t<id>, double>);
static_assert(based::arity_v<id> == 1);
int main()
{
static_assert(std::same_as<based::domain_t<identity<int>>, std::tuple<int>>);
static_assert(based::arity_v<identity<int>> == 1);
static_assert(based::Procedure<id>);
static_assert(based::Procedure<ii>);
static_assert(based::RegularProcedure<id>);
static_assert(!based::RegularProcedure<ii>);
using ad = add<double, double>;
using ai = add<irregular, irregular>;
using aid = add<irregular, double>;
using adi = add<double, irregular>;
static_assert(std::same_as<based::domain_t<ad>, std::tuple<double, double>>);
static_assert(std::same_as<based::codomain_t<ad>, double>);
static_assert(based::arity_v<ad> == 2);
static_assert(based::Procedure<identity<int>>);
static_assert(based::Procedure<identity<irregular>>);
static_assert(based::Procedure<ad>);
static_assert(based::Procedure<ai>);
static_assert(based::Procedure<aid>);
static_assert(based::Procedure<adi>);
static_assert(!based::Procedure<identity_wrong_input_tuple>);
static_assert(based::RegularProcedure<ad>);
static_assert(!based::RegularProcedure<ai>);
static_assert(!based::RegularProcedure<aid>);
static_assert(!based::RegularProcedure<adi>);
static_assert(based::RegularProcedure<identity<int>>);
static_assert(!based::RegularProcedure<identity<irregular>>);
static const auto l1 = [](double a) { return a; };
static_assert(based::RegularProcedure<decltype(l1)>);
static_assert(!based::RegularProcedure<identity_wrong_input_tuple_irregular>);
static const auto l2 = [](irregular /* a */) { return 1; };
static_assert(!based::RegularProcedure<decltype(l2)>);
}
diff --git a/include/based/type_traits.hpp b/include/based/type_traits.hpp
@@ -9,18 +9,19 @@ namespace based
template<typename T>
concept Regular = std::regular<T>;
template<typename>
struct is_tuple : std::false_type
{
};
template<typename Fun>
concept FreeProcedure = std::is_function_v<Fun>;
template<typename... T>
struct is_tuple<std::tuple<T...>> : std::true_type
{
};
template<typename Fun>
concept MemberProcedure = std::is_member_function_pointer_v<std::decay_t<Fun>>;
template<typename T>
inline constexpr bool is_tuple_v = is_tuple<T>::value;
template<typename Fun>
concept FunctorProcedure = std::is_class_v<std::decay_t<Fun>>
&& requires(Fun&& t) { &std::decay_t<Fun>::operator(); };
template<typename P>
concept Procedure =
FreeProcedure<P> || MemberProcedure<P> || FunctorProcedure<P>;
template<class>
struct is_regular_tuple : std::false_type
@@ -39,48 +40,109 @@ inline constexpr bool is_regular_tuple_v = is_regular_tuple<T>::value;
template<class T>
concept RegularTuple = is_regular_tuple_v<T>;
template<typename P>
struct domain
template<typename>
struct signature;
template<typename Ret, typename... Args>
struct signature<Ret(Args...)>
{
using type = std::remove_reference_t<P>::input_types;
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
};
template<typename T>
using domain_t = typename domain<T>::type;
template<typename Ret, typename Obj, typename... Args>
struct signature<Ret (Obj::*)(Args...)>
{
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
};
template<typename P>
struct codomain
template<typename Ret, typename Obj, typename... Args>
struct signature<Ret (Obj::*)(Args...) const>
{
using type = std::remove_reference_t<P>::output_type;
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
};
template<typename T>
using codomain_t = typename codomain<T>::type;
template<typename Ret, typename Obj, typename... Args>
struct signature<Ret (Obj::*)(Args...) volatile>
{
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
};
template<typename Ret, typename Obj, typename... Args>
struct signature<Ret (Obj::*)(Args...) const volatile>
{
using arg_type = std::tuple<Args...>;
using ret_type = Ret;
};
template<typename>
struct domain;
template<FunctorProcedure P>
struct domain<P>
{
using type = signature<decltype(&std::decay_t<P>::operator())>::arg_type;
};
template<FreeProcedure P>
struct domain<P>
{
using type = signature<P>::arg_type;
};
template<MemberProcedure P>
struct domain<P>
{
using type = signature<std::decay_t<P>>::arg_type;
};
template<typename P>
concept Procedure = requires {
typename domain_t<P>;
typename codomain_t<P>;
requires(is_tuple_v<domain_t<P>>);
using domain_t = domain<P>::type;
template<typename>
struct codomain;
template<FunctorProcedure P>
struct codomain<P>
{
using type = signature<decltype(&std::decay_t<P>::operator())>::ret_type;
};
template<Procedure P>
template<FreeProcedure P>
struct codomain<P>
{
using type = signature<P>::ret_type;
};
template<MemberProcedure P>
struct codomain<P>
{
using type = signature<std::decay_t<P>>::ret_type;
};
template<typename P>
using codomain_t = typename codomain<P>::type;
template<typename P>
struct arity
{
static constexpr auto value = std::tuple_size<domain_t<P>>::value;
};
template<Procedure P>
template<typename P>
inline constexpr auto arity_v = arity<P>::value;
template<Procedure P, std::size_t Idx>
template<typename P, std::size_t Idx>
requires requires { Idx < arity_v<P>; }
struct domain_elem
{
using type = std::tuple_element_t<Idx, domain_t<P>>;
};
template<Procedure P, std::size_t Idx>
template<typename P, std::size_t Idx>
using domain_elem_t = typename domain_elem<P, Idx>::type;
template<typename P>
@@ -94,5 +156,4 @@ concept RegularProcedure = requires {
template<typename P>
concept FunctionalProcedure = requires { requires(RegularProcedure<P>); };
*/
} // namespace based