namespace detail
{
template<class V, class F, class... Args>
constexpr bool negate_invocable_impl = false;
template<class F, class... Args>
constexpr bool negate_invocable_impl<std::void_t<decltype(
!std::invoke(std::declval<F>(), std::declval<Args>()...))>, F, Args...> = true;
template<class F, class... Args>
constexpr bool negate_invocable_v = negate_invocable_impl<void, F, Args...>;
template<class F>
struct not_fn_t
{
F f;
template<class... Args,
std::enable_if_t<negate_invocable_v<F&, Args...>, int> = 0>
constexpr decltype(auto) operator()(Args&&... args) &
noexcept(noexcept(!std::invoke(f, std::forward<Args>(args)...)))
{
return !std::invoke(f, std::forward<Args>(args)...);
}
template<class... Args,
std::enable_if_t<negate_invocable_v<const F&, Args...>, int> = 0>
constexpr decltype(auto) operator()(Args&&... args) const&
noexcept(noexcept(!std::invoke(f, std::forward<Args>(args)...)))
{
return !std::invoke(f, std::forward<Args>(args)...);
}
template<class... Args,
std::enable_if_t<negate_invocable_v<F, Args...>, int> = 0>
constexpr decltype(auto) operator()(Args&&... args) &&
noexcept(noexcept(!std::invoke(std::move(f), std::forward<Args>(args)...)))
{
return !std::invoke(std::move(f), std::forward<Args>(args)...);
}
template<class... Args,
std::enable_if_t<negate_invocable_v<const F, Args...>, int> = 0>
constexpr decltype(auto) operator()(Args&&... args) const&&
noexcept(noexcept(!std::invoke(std::move(f), std::forward<Args>(args)...)))
{
return !std::invoke(std::move(f), std::forward<Args>(args)...);
}
// Deleted overloads are needed since C++20
// for preventing a non-equivalent but well-formed overload to be selected.
template<class... Args,
std::enable_if_t<!negate_invocable_v<F&, Args...>, int> = 0>
void operator()(Args&&...) & = delete;
template<class... Args,
std::enable_if_t<!negate_invocable_v<const F&, Args...>, int> = 0>
void operator()(Args&&...) const& = delete;
template<class... Args,
std::enable_if_t<!negate_invocable_v<F, Args...>, int> = 0>
void operator()(Args&&...) && = delete;
template<class... Args,
std::enable_if_t<!negate_invocable_v<const F, Args...>, int> = 0>
void operator()(Args&&...) const&& = delete;
};
}
template<class F>
constexpr detail::not_fn_t<std::decay_t<F>> not_fn(F&& f)
{
return {std::forward<F>(f)};
}