Commit 5f299117 authored by tqcq's avatar tqcq
Browse files

feat update invoke_result

parent 778d24b8
Loading
Loading
Loading
Loading
+182 −153
Original line number Diff line number Diff line
@@ -18,13 +18,15 @@ namespace detail {
#define EGGS_FWD(...) static_cast<decltype(__VA_ARGS__) &&>(__VA_ARGS__)

///////////////////////////////////////////////////////////////////////////
template<typename C, typename T, bool Ref, bool RefWrapper, bool IsFunction = std::is_function<T>::value>
template <typename C, typename T, bool Ref, bool RefWrapper,
          bool IsFunction = std::is_function<T>::value>
struct invoke_mem_ptr;

// when `pm` is a pointer to member of a class `C` and
// `is_base_of_v<C, remove_reference_t<T>>` is `true`;
template <typename C, typename T>
struct invoke_mem_ptr<C, T, /*Ref=*/true, /*RefWrapper=*/false, /*IsFunction=*/false> {
struct invoke_mem_ptr<C, T, /*Ref=*/true, /*RefWrapper=*/false,
                      /*IsFunction=*/false> {
  T C::*pm;

#if !__cpp_aggregate_paren_init
@@ -32,14 +34,15 @@ struct invoke_mem_ptr<C, T, /*Ref=*/true, /*RefWrapper=*/false, /*IsFunction=*/f
#endif

  template <typename T1>
    constexpr auto operator()(T1 &&t1) const noexcept(noexcept(EGGS_FWD(t1).*pm)) -> decltype(EGGS_FWD(t1).*pm)
    {
  constexpr auto operator()(T1 &&t1) const
      noexcept(noexcept(EGGS_FWD(t1).*pm)) -> decltype(EGGS_FWD(t1).*pm) {
    return EGGS_FWD(t1).*pm;
  }
};

template <typename C, typename T>
struct invoke_mem_ptr<C, T, /*Ref=*/true, /*RefWrapper=*/false, /*IsFunction=*/true> {
struct invoke_mem_ptr<C, T, /*Ref=*/true, /*RefWrapper=*/false,
                      /*IsFunction=*/true> {
  T C::*pm;

#if !__cpp_aggregate_paren_init
@@ -47,9 +50,9 @@ struct invoke_mem_ptr<C, T, /*Ref=*/true, /*RefWrapper=*/false, /*IsFunction=*/t
#endif

  template <typename T1, typename... Tn>
    constexpr auto operator()(T1 &&t1, Tn &&...tn) const noexcept(noexcept((EGGS_FWD(t1).*pm)(EGGS_FWD(tn)...)))
        -> decltype((EGGS_FWD(t1).*pm)(EGGS_FWD(tn)...))
    {
  constexpr auto operator()(T1 &&t1, Tn &&...tn) const
      noexcept(noexcept((EGGS_FWD(t1).*pm)(EGGS_FWD(tn)...)))
          -> decltype((EGGS_FWD(t1).*pm)(EGGS_FWD(tn)...)) {
    return (EGGS_FWD(t1).*pm)(EGGS_FWD(tn)...);
  }
};
@@ -57,7 +60,8 @@ struct invoke_mem_ptr<C, T, /*Ref=*/true, /*RefWrapper=*/false, /*IsFunction=*/t
// when `pm` is a pointer to member of a class `C` and
// `remove_cvref_t<T>` is a specialization of `reference_wrapper`;
template <typename C, typename T>
struct invoke_mem_ptr<C, T, /*Ref=*/false, /*RefWrapper=*/true, /*IsFunction=*/false> {
struct invoke_mem_ptr<C, T, /*Ref=*/false, /*RefWrapper=*/true,
                      /*IsFunction=*/false> {
  T C::*pm;

#if !__cpp_aggregate_paren_init
@@ -65,14 +69,15 @@ struct invoke_mem_ptr<C, T, /*Ref=*/false, /*RefWrapper=*/true, /*IsFunction=*/f
#endif

  template <typename T1>
    constexpr auto operator()(T1 &&t1) const noexcept(noexcept(t1.get().*pm)) -> decltype(t1.get().*pm)
    {
  constexpr auto operator()(T1 &&t1) const
      noexcept(noexcept(t1.get().*pm)) -> decltype(t1.get().*pm) {
    return t1.get().*pm;
  }
};

template <typename C, typename T>
struct invoke_mem_ptr<C, T, /*Ref=*/false, /*RefWrapper=*/true, /*IsFunction=*/true> {
struct invoke_mem_ptr<C, T, /*Ref=*/false, /*RefWrapper=*/true,
                      /*IsFunction=*/true> {
  T C::*pm;

#if !__cpp_aggregate_paren_init
@@ -80,9 +85,9 @@ struct invoke_mem_ptr<C, T, /*Ref=*/false, /*RefWrapper=*/true, /*IsFunction=*/t
#endif

  template <typename T1, typename... Tn>
    constexpr auto operator()(T1 &&t1, Tn &&...tn) const noexcept(noexcept((t1.get().*pm)(EGGS_FWD(tn)...)))
        -> decltype((t1.get().*pm)(EGGS_FWD(tn)...))
    {
  constexpr auto operator()(T1 &&t1, Tn &&...tn) const
      noexcept(noexcept((t1.get().*pm)(EGGS_FWD(tn)...)))
          -> decltype((t1.get().*pm)(EGGS_FWD(tn)...)) {
    return (t1.get().*pm)(EGGS_FWD(tn)...);
  }
};
@@ -90,7 +95,8 @@ struct invoke_mem_ptr<C, T, /*Ref=*/false, /*RefWrapper=*/true, /*IsFunction=*/t
// when `pm` is a pointer to member of a class `C` and `T` does not
// satisfy the previous two items;
template <typename C, typename T>
struct invoke_mem_ptr<C, T, /*Ref=*/false, /*RefWrapper=*/false, /*IsFunction=*/false> {
struct invoke_mem_ptr<C, T, /*Ref=*/false, /*RefWrapper=*/false,
                      /*IsFunction=*/false> {
  T C::*pm;

#if !__cpp_aggregate_paren_init
@@ -98,14 +104,15 @@ struct invoke_mem_ptr<C, T, /*Ref=*/false, /*RefWrapper=*/false, /*IsFunction=*/
#endif

  template <typename T1>
    constexpr auto operator()(T1 &&t1) const noexcept(noexcept((*EGGS_FWD(t1)).*pm)) -> decltype((*EGGS_FWD(t1)).*pm)
    {
  constexpr auto operator()(T1 &&t1) const
      noexcept(noexcept((*EGGS_FWD(t1)).*pm)) -> decltype((*EGGS_FWD(t1)).*pm) {
    return (*EGGS_FWD(t1)).*pm;
  }
};

template <typename C, typename T>
struct invoke_mem_ptr<C, T, /*Ref=*/false, /*RefWrapper=*/false, /*IsFunction=*/true> {
struct invoke_mem_ptr<C, T, /*Ref=*/false, /*RefWrapper=*/false,
                      /*IsFunction=*/true> {
  T C::*pm;

#if !__cpp_aggregate_paren_init
@@ -113,26 +120,25 @@ struct invoke_mem_ptr<C, T, /*Ref=*/false, /*RefWrapper=*/false, /*IsFunction=*/
#endif

  template <typename T1, typename... Tn>
    constexpr auto operator()(T1 &&t1, Tn &&...tn) const noexcept(noexcept(((*EGGS_FWD(t1)).*pm)(EGGS_FWD(tn)...)))
        -> decltype(((*EGGS_FWD(t1)).*pm)(EGGS_FWD(tn)...))
    {
  constexpr auto operator()(T1 &&t1, Tn &&...tn) const
      noexcept(noexcept(((*EGGS_FWD(t1)).*pm)(EGGS_FWD(tn)...)))
          -> decltype(((*EGGS_FWD(t1)).*pm)(EGGS_FWD(tn)...)) {
    return ((*EGGS_FWD(t1)).*pm)(EGGS_FWD(tn)...);
  }
};

///////////////////////////////////////////////////////////////////////////
template<typename F>
auto invoke(F &&, ...) -> F &&;
template <typename F> auto invoke(F &&, ...) -> F &&;

template <typename T, typename C, typename T1>
auto invoke(T C::*, T1 const &, ...) -> invoke_mem_ptr<C,
                                                       T,
auto invoke(T C::*, T1 const &,
            ...) -> invoke_mem_ptr<C, T,
                                   /*Ref=*/std::is_base_of<C, T1>::value,
                                   /*RefWrapper=*/false>;

template <typename T, typename C, typename X>
auto invoke(T C::*, std::reference_wrapper<X>, ...) -> invoke_mem_ptr<C,
                                                                      T,
auto invoke(T C::*, std::reference_wrapper<X>,
            ...) -> invoke_mem_ptr<C, T,
                                   /*Ref=*/false,
                                   /*RefWrapper=*/true>;

@@ -141,11 +147,16 @@ auto invoke(T C::*, std::reference_wrapper<X>, ...) -> invoke_mem_ptr<C,
//! - _Returns_: `INVOKE(F __VA_OPT__(,) __VA_ARGS__)`.
#if __cplusplus > 201703L // C++20: P0306
#define EGGS_INVOKE(F, ...)                                                    \
    (static_cast<decltype(::eggs::detail::invoke(F __VA_OPT__(, ) __VA_ARGS__))>(F)(__VA_ARGS__))
  (static_cast<decltype(::eggs::detail::invoke(                                \
       F __VA_OPT__(, ) __VA_ARGS__))>(F)(__VA_ARGS__))
#elif _MSVC_TRADITIONAL
#define EGGS_INVOKE(F, ...) (static_cast<decltype(::eggs::detail::invoke(F, __VA_ARGS__))>(F)(__VA_ARGS__))
#define EGGS_INVOKE(F, ...)                                                    \
  (static_cast<decltype(::eggs::detail::invoke(F, __VA_ARGS__))>(F)(           \
      __VA_ARGS__))
#else
#define EGGS_INVOKE(F, ...) (static_cast<decltype(::eggs::detail::invoke(F, ##__VA_ARGS__))>(F)(__VA_ARGS__))
#define EGGS_INVOKE(F, ...)                                                    \
  (static_cast<decltype(::eggs::detail::invoke(F, ##__VA_ARGS__))>(F)(         \
      __VA_ARGS__))
#endif

///////////////////////////////////////////////////////////////////////////
@@ -157,21 +168,20 @@ private:

public:
  template <typename F, typename... Args>
    static constexpr auto
    call(F &&f, Args &&...args) noexcept(noexcept(conversion(EGGS_INVOKE(EGGS_FWD(f), EGGS_FWD(args)...))))
        -> decltype(conversion(EGGS_INVOKE(EGGS_FWD(f), EGGS_FWD(args)...)))
    {
  static constexpr auto call(F &&f, Args &&...args) noexcept(
      noexcept(conversion(EGGS_INVOKE(EGGS_FWD(f), EGGS_FWD(args)...))))
      -> decltype(conversion(EGGS_INVOKE(EGGS_FWD(f), EGGS_FWD(args)...))) {
    return EGGS_INVOKE(EGGS_FWD(f), EGGS_FWD(args)...);
  }
};

// `static_cast<void>(INVOKE(f, t1, t2, ..., tN))` if `R` is _cv_ `void`.
template<typename R>
struct invoke_r<R, void> {
template <typename R> struct invoke_r<R, void> {
  template <typename F, typename... Args>
    static constexpr auto call(F &&f, Args &&...args) noexcept(noexcept(EGGS_INVOKE(EGGS_FWD(f), EGGS_FWD(args)...)))
        -> decltype(static_cast<void>(EGGS_INVOKE(EGGS_FWD(f), EGGS_FWD(args)...)))
    {
  static constexpr auto call(F &&f, Args &&...args) noexcept(
      noexcept(EGGS_INVOKE(EGGS_FWD(f), EGGS_FWD(args)...)))
      -> decltype(static_cast<void>(EGGS_INVOKE(EGGS_FWD(f),
                                                EGGS_FWD(args)...))) {
    return static_cast<void>(EGGS_INVOKE(EGGS_FWD(f), EGGS_FWD(args)...));
  }
};
@@ -187,11 +197,12 @@ struct invoke_r<R, void> {
namespace eggs {
///////////////////////////////////////////////////////////////////////////
namespace detail {
template<typename T, typename Enable = void>
struct invoke_result_impl {};
template <typename T, typename Enable = void> struct invoke_result_impl {};

template <typename F, typename... Ts>
struct invoke_result_impl<F(Ts...), decltype((void) EGGS_INVOKE(std::declval<F>(), std::declval<Ts>()...))> {
struct invoke_result_impl<F(Ts...),
                          decltype((void)EGGS_INVOKE(std::declval<F>(),
                                                     std::declval<Ts>()...))> {
  using type = decltype(EGGS_INVOKE(std::declval<F>(), std::declval<Ts>()...));
};
} // namespace detail
@@ -223,7 +234,9 @@ template<typename T, typename Enable = void>
struct is_invocable_impl : std::false_type {};

template <typename F, typename... Ts>
struct is_invocable_impl<F(Ts...), decltype((void) EGGS_INVOKE(std::declval<F>(), std::declval<Ts>()...))>
struct is_invocable_impl<F(Ts...),
                         decltype((void)EGGS_INVOKE(std::declval<F>(),
                                                    std::declval<Ts>()...))>
    : std::true_type {};
} // namespace detail

@@ -237,7 +250,8 @@ struct is_invocable_impl<F(Ts...), decltype((void) EGGS_INVOKE(std::declval<F>()
//!   `ArgTypes` shall be complete types, _cv_ `void`, or arrays of
//!   unknown bound.
template <typename Fn, typename... ArgTypes>
struct is_invocable : detail::is_invocable_impl<Fn && (ArgTypes && ...)>::type {};
struct is_invocable : detail::is_invocable_impl<Fn && (ArgTypes && ...)>::type {
};

#if __cpp_variable_templates
//! template <class Fn, class... ArgTypes> // (C++14)
@@ -256,7 +270,9 @@ template<typename T, typename R, typename Enable = void>
struct is_invocable_r_impl : std::false_type {};

template <typename F, typename... Ts, typename R>
struct is_invocable_r_impl<F(Ts...), R, decltype((void) EGGS_INVOKE_R(R, std::declval<F>(), std::declval<Ts>()...))>
struct is_invocable_r_impl<F(Ts...), R,
                           decltype((void)EGGS_INVOKE_R(R, std::declval<F>(),
                                                        std::declval<Ts>()...))>
    : std::true_type {};
} // namespace detail

@@ -270,7 +286,8 @@ struct is_invocable_r_impl<F(Ts...), R, decltype((void) EGGS_INVOKE_R(R, std::de
//!   `ArgTypes` shall be complete types, _cv_ `void`, or arrays of
//!   unknown bound.
template <typename R, typename Fn, typename... ArgTypes>
struct is_invocable_r : detail::is_invocable_r_impl<Fn && (ArgTypes && ...), R>::type {};
struct is_invocable_r
    : detail::is_invocable_r_impl<Fn && (ArgTypes && ...), R>::type {};

#if __cpp_variable_templates
//! template <class R, class Fn, class... ArgTypes> // (C++14)
@@ -289,8 +306,12 @@ template<typename T, typename Enable = void>
struct is_nothrow_invocable_impl : std::false_type {};

template <typename F, typename... Ts>
struct is_nothrow_invocable_impl<F(Ts...), decltype((void) EGGS_INVOKE(std::declval<F>(), std::declval<Ts>()...))>
    : std::integral_constant<bool, noexcept(EGGS_INVOKE(std::declval<F>(), std::declval<Ts>()...))> {};
struct is_nothrow_invocable_impl<F(Ts...),
                                 decltype((void)EGGS_INVOKE(
                                     std::declval<F>(), std::declval<Ts>()...))>
    : std::integral_constant<bool,
                             noexcept(EGGS_INVOKE(std::declval<F>(),
                                                  std::declval<Ts>()...))> {};
} // namespace detail

//! template <class Fn, class... ArgTypes> struct is_nothrow_invocable;
@@ -303,7 +324,8 @@ struct is_nothrow_invocable_impl<F(Ts...), decltype((void) EGGS_INVOKE(std::decl
//!   `ArgTypes` shall be complete types, _cv_ `void`, or arrays of
//!   unknown bound.
template <typename Fn, typename... ArgTypes>
struct is_nothrow_invocable : detail::is_nothrow_invocable_impl<Fn && (ArgTypes && ...)>::type {};
struct is_nothrow_invocable
    : detail::is_nothrow_invocable_impl<Fn && (ArgTypes && ...)>::type {};

#if __cpp_variable_templates
//! template <class Fn, class... ArgTypes> // (C++14)
@@ -313,7 +335,8 @@ template<typename Fn, typename... ArgTypes>
#if __cpp_inline_variables
inline
#endif
    constexpr bool is_nothrow_invocable_v = is_nothrow_invocable<Fn, ArgTypes...>::value;
    constexpr bool is_nothrow_invocable_v =
        is_nothrow_invocable<Fn, ArgTypes...>::value;
#endif

///////////////////////////////////////////////////////////////////////////
@@ -322,23 +345,27 @@ template<typename T, typename R, typename Enable = void>
struct is_nothrow_invocable_r_impl : std::false_type {};

template <typename F, typename... Ts, typename R>
struct is_nothrow_invocable_r_impl<F(Ts...),
                                   R,
struct is_nothrow_invocable_r_impl<
    F(Ts...), R,
    decltype((void)EGGS_INVOKE_R(R, std::declval<F>(), std::declval<Ts>()...))>
    : std::integral_constant<bool, noexcept(EGGS_INVOKE_R(R, std::declval<F>(), std::declval<Ts>()...))> {};
    : std::integral_constant<bool,
                             noexcept(EGGS_INVOKE_R(R, std::declval<F>(),
                                                    std::declval<Ts>()...))> {};
} // namespace detail

//! template <class R, class Fn, class... ArgTypes> struct is_nothrow_invocable_r;
//! template <class R, class Fn, class... ArgTypes> struct
//! is_nothrow_invocable_r;
//!
//! - _Condition_: `eggs::is_invocable_r_v<R, Fn, ArgTypes...>` is `true`
//!   and the expression `INVOKE(std::declval<Fn>(), std::declval<ArgTypes>()...)`
//!   is known not to throw any exceptions.
//!   and the expression `INVOKE(std::declval<Fn>(),
//!   std::declval<ArgTypes>()...)` is known not to throw any exceptions.
//!
//! - _Comments_: `Fn`, `R`, and all types in the template parameter pack
//!   `ArgTypes` shall be complete types, _cv_ `void`, or arrays of
//!   unknown bound.
template <typename R, typename Fn, typename... ArgTypes>
struct is_nothrow_invocable_r : detail::is_nothrow_invocable_r_impl<Fn && (ArgTypes && ...), R>::type {};
struct is_nothrow_invocable_r
    : detail::is_nothrow_invocable_r_impl<Fn && (ArgTypes && ...), R>::type {};

#if __cpp_variable_templates
//! template <class R, class Fn, class... ArgTypes> // (C++14)
@@ -348,7 +375,8 @@ template<typename R, typename Fn, typename... ArgTypes>
#if __cpp_inline_variables
inline
#endif
    constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<R, Fn, ArgTypes...>::value;
    constexpr bool is_nothrow_invocable_r_v =
        is_nothrow_invocable_r<R, Fn, ArgTypes...>::value;
#endif

///////////////////////////////////////////////////////////////////////////
@@ -361,10 +389,9 @@ inline
//! - _Remarks_: This function shall not participate in overload resolution
//!   unless `eggs::is_invocable_v<F, Args...>` is `true`.
template <typename Fn, typename... ArgTypes>
constexpr auto
invoke(Fn &&f, ArgTypes &&...args) noexcept(noexcept(EGGS_INVOKE(EGGS_FWD(f), EGGS_FWD(args)...)))
    -> decltype(EGGS_INVOKE(EGGS_FWD(f), EGGS_FWD(args)...))
{
constexpr auto invoke(Fn &&f, ArgTypes &&...args) noexcept(
    noexcept(EGGS_INVOKE(EGGS_FWD(f), EGGS_FWD(args)...)))
    -> decltype(EGGS_INVOKE(EGGS_FWD(f), EGGS_FWD(args)...)) {
  return EGGS_INVOKE(EGGS_FWD(f), EGGS_FWD(args)...);
}

@@ -378,14 +405,16 @@ invoke(Fn &&f, ArgTypes &&...args) noexcept(noexcept(EGGS_INVOKE(EGGS_FWD(f), EG
//! - _Remarks_: This function shall not participate in overload resolution
//!   unless `eggs::is_invocable_r_v<R, F, Args...>` is `true`.
template <typename R, typename Fn, typename... ArgTypes>
constexpr auto
invoke_r(Fn &&f, ArgTypes &&...args) noexcept(noexcept(EGGS_INVOKE_R(R, EGGS_FWD(f), EGGS_FWD(args)...)))
    -> decltype(EGGS_INVOKE_R(R, EGGS_FWD(f), EGGS_FWD(args)...))
{
constexpr auto invoke_r(Fn &&f, ArgTypes &&...args) noexcept(
    noexcept(EGGS_INVOKE_R(R, EGGS_FWD(f), EGGS_FWD(args)...)))
    -> decltype(EGGS_INVOKE_R(R, EGGS_FWD(f), EGGS_FWD(args)...)) {
  return EGGS_INVOKE_R(R, EGGS_FWD(f), EGGS_FWD(args)...);
}

#undef EGGS_FWD
} // namespace eggs

namespace tile {
using namespace eggs;
}
#endif /*EGGS_INVOKE_HPP*/