Skip to content

Latest commit

 

History

History
207 lines (158 loc) · 5.44 KB

273.md

File metadata and controls

207 lines (158 loc) · 5.44 KB
Info

Example

static_assert([]<class T>{ return std::integral<T>; }.operator()<int>());

struct f { auto foo() -> void; };
static_assert([](auto t){ return requires { t.foo(); }; }(f{}));

https://godbolt.org/z/3KbevGYK3

Puzzle

  • Can you implement concept fooable which is satisfied if its parameters satisfies given concepts?
template<class T, auto... Ts>
concept fooable; // TODO

struct bar  { };
static_assert(not fooable<bar>);

struct foo1 { void foo(int); };
static_assert(fooable<foo1, []<class T> { return std::integral<T>; }>);

struct foo2 { void foo(int, short); };
static_assert(fooable<foo2, []<class T> { return std::integral<T>; },
                            []<class T> { return std::same_as<short, T>; }>);

https://godbolt.org/z/ja439rq4o

Solutions

template <class T, auto... ConceptCheckers>
concept fooable = requires(T t) { &T::foo; };

https://godbolt.org/z/KrWrvze85

namespace detail {

template <typename...>
struct type_list {};

template <auto...>
struct value_list {};

template <typename T>
concept has_foo = requires(T t) { &T::foo; };

template <typename>
struct foo_function_traits;

template <typename TBase, typename TReturn, typename... TArgs>
struct foo_function_traits<TReturn (TBase::*)(TArgs...)> {
    using arg_types = type_list<TArgs...>;
};

template <typename... TArgs, auto... ConceptCheckers>
[[nodiscard]] consteval auto check_foo_args(type_list<TArgs...>,
                                            value_list<ConceptCheckers...>) {
    if constexpr (sizeof...(TArgs) != sizeof...(ConceptCheckers)) {
        return false;
    } else {
        return (... and ConceptCheckers.template operator()<TArgs>());
    }
}

}  // namespace detail

template <class T, auto... ConceptCheckers>
concept fooable =
    detail::has_foo<T> and
    detail::check_foo_args(
        typename detail::foo_function_traits<decltype(&T::foo)>::arg_types{},
        detail::value_list<ConceptCheckers...>{});

https://godbolt.org/z/ac6M6vKsv

template <auto Constraint>
struct ArgConstraint {
    template <typename T>
        requires (Constraint.template operator()<T>())
    operator T();
};

template<class T, auto... Ts>
concept fooable = requires (T x) { x.foo(ArgConstraint<Ts>{}...); }

https://godbolt.org/z/3e6rPGT4f

template<typename T, typename R, typename ... Args>
consteval auto get_arguments(R(T::*)(Args...))
{
    return std::tuple<Args...>();
}

template <class ArgumentTuple, class FunctionTuple>
consteval decltype(auto) for_each(ArgumentTuple && tuple, FunctionTuple && f)
{
    if constexpr (std::tuple_size_v<ArgumentTuple> != std::tuple_size_v<FunctionTuple>)
        return false;
    
    return [] <std::size_t... I>
        (ArgumentTuple && tuple, FunctionTuple&& f, std::index_sequence<I...>)
        {
            return (std::get<I>(f).template operator()<std::remove_reference_t<decltype(std::get<I>(tuple))>>() && ...);
        }
        (std::forward<ArgumentTuple>(tuple), std::forward<FunctionTuple>(f),
        std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<ArgumentTuple>>>{});
}

template<class T, auto... Ts>
concept fooable = for_each(get_arguments(&T::foo), std::tuple(Ts...));

https://godbolt.org/z/YKs9zGKqz

template <class T, class C>
using satifies = boost::mp11::mp_bool<C{}.template operator()<T>()>;

template <class T>
struct indexed_arg {
  template <class N>
  using fn = typename boost::mpl::at<T, N>::type;
};

template <class F>
using arg_list = boost::mp11::mp_pop_front<boost::mp11::mp_transform_q<
      indexed_arg<boost::function_types::parameter_types<F>>,
      boost::mp11::mp_iota_c<boost::function_types::function_arity<F>::value>>>;

template <class T, auto... Ts>
concept fooable = boost::mp11::mp_apply<boost::mp11::mp_all,
  boost::mp11::mp_transform<
    satifies,
    arg_list<decltype(&T::foo)>,
    boost::mp11::mp_list<decltype(Ts)...>>>::value;

https://godbolt.org/z/cev74a6jq

template<class...> struct type_list{};
template<class> struct function_traits;
template<class R, class B, class... Ts>
struct function_traits<R(B::*)(Ts...)> {
  using args_t = type_list<Ts...>;
};

template<class T, auto... Ts>
concept fooable = []<class... TArgs>(type_list<TArgs...>) {
  return (decltype(Ts){}.template operator()<TArgs>() and ...);
}(typename function_traits<decltype(&T::foo)>::args_t{});

https://godbolt.org/z/4hxe4EYfq

template <class T, auto... Vs>
concept fooable = []<class R, class... Args>(R (T::*)(Args...), auto... tests) {
  return (... and tests.template operator()<Args>());
}(&T::foo, Vs...);

https://godbolt.org/z/ar59cM1rW

template<auto Validate>
struct AnyType {
    template<class T>
    operator T() {
        static_assert( Validate.template operator()<T>() );
        return T{}; }
};

template<class T, auto... Ts>
concept fooable = requires(T v ) {
    v.foo(AnyType<Ts>{} ...);
};

https://godbolt.org/z/avvbGdbK9

template <auto Constraint> struct satisfies {
  template <class T> requires (Constraint.template operator()<T>()) operator T();
};

template<class T, auto... Ts>
concept fooable = requires (T t) { t.foo(satisfies<Ts>{}...); };

https://godbolt.org/z/jz7Yrf4Wr