Spec-Zone.ru › C++

std::not_fn

Определено в заголовке <functional>
template< class F >
/* unspecified */ not_fn( F&& f );
(1) (с C++17)
(constexpr с C++20)
template< auto ConstFn >
constexpr /* unspecified */ not_fn() noexcept;
(2) (с C++26)
1) Создаёт оболочку для вызова, возвращающую отрицание вызываемого объекта, который она содержит.
2) Создаёт оболочку для вызова, возвращающую отрицание статически определённого вызываемого целевого объекта. Программа неверна, если ConstFn является нулевым указателем или нулевым указателем на член.

Параметры

f - объект, из которого создаётся объект Callable, содержащийся в оболочке
Требования к типу
-std::decay_t<F> должен удовлетворять требованиям Callable и MoveConstructible.
-std::is_constructible_v<std::decay_t<F>, F> должен быть true.

Возвращаемое значение

1) Объект-функция неопределённого типа T. Он имеет следующие члены.

std::not_fn тип возвращаемого значения

Члены-объекты

Тип возвращаемого значения std::not_fn содержит член-объект типа std::decay_t<F>.

Конструкторы

explicit T( F&& f );
(1) (с C++17)
(constexpr с C++20)
(только для иллюстрации*)
T( T&& f ) = default;
T( const T& f ) = default;
(2) (с C++17)
1) Конструктор прямой инициализирует член-объект (типа std::decay_t<F>) из std::forward<F>(f). Бросает любое исключение, брошенное выбранным конструктором.
2) Поскольку std::decay_t<F> должен быть MoveConstructible, возвращаемая оболочка для вызова всегда MoveConstructible, и является CopyConstructible, если std::decay_t<F> является CopyConstructible.

Явно заданные по умолчанию определения делают тип возвращаемого значения неприсваиваемым.

Не определено, задаются ли эти конструкторы явно по умолчанию и присваивается ли тип возвращаемого значения.

Член-функция operator()

(1)
template< class... Args >
auto operator()( Args&&... args ) &
-> decltype(!std::declval<
    std::invoke_result_t<std::decay_t<F>&, Args...>>());
template< class... Args >
auto operator()( Args&&... args ) const&
-> decltype(!std::declval<
    std::invoke_result_t<std::decay_t<F> const&, Args...>>());
(с C++17)
(до C++20)
template< class... Args >
constexpr auto operator()( Args&&... args ) &
    noexcept(/* see below */)
-> decltype(!std::declval<
    std::invoke_result_t<std::decay_t<F>&, Args...>>());
template< class... Args >
constexpr auto operator()( Args&&... args ) const&
    noexcept(/* see below */)
-> decltype(!std::declval<
    std::invoke_result_t<std::decay_t<F> const&, Args...>>());
(с C++20)
(2)
template< class... Args >
auto operator()( Args&&... args ) &&
-> decltype(!std::declval<
    std::invoke_result_t<std::decay_t<F>, Args...>>());
template< class... Args >
auto operator()( Args&&... args ) const&&
-> decltype(!std::declval<
    std::invoke_result_t<std::decay_t<F> const, Args...>>());
(с C++17)
(до C++20)
template< class... Args >
constexpr auto operator()( Args&&... args ) &&
    noexcept(/* see below */)
-> decltype(!std::declval<
    std::invoke_result_t<std::decay_t<F>, Args...>>());
template< class... Args >
constexpr auto operator()( Args&&... args ) const&&
    noexcept(/* see below */)
-> decltype(!std::declval<
    std::invoke_result_t<std::decay_t<F> const, Args...>>());
(с C++20)

Пусть fd — это член-объект типа std::decay_t<F>.

1) Эквивалентно return !std::invoke(fd, std::forward<Args>(args)...); 2) Эквивалентно return !std::invoke(std::move(fd), std::forward<Args>(args)...);

При вызове результата, если подстановка в тип возвращаемого значения первоначально выбранной перегрузки оператора() терпит неудачу, может быть выбрана другая перегрузка.

(с C++17)
(до C++20)
1) Экспрессивно эквивалентно !std::invoke(fd, std::forward<Args>(args)...) 2) Экспрессивно эквивалентно !std::invoke(std::move(fd), std::forward<Args>(args)...)

При вызове результата, если подстановка в тип возвращаемого значения первоначально выбранной перегрузки оператора() терпит неудачу, вызов некорректен, что также может быть ошибкой подстановки.

(с C++20)
2) Значение следующего типа.

std::not_fn тип возвращаемого значения без состояния

Тип возвращаемого значения — это CopyConstructible бессостоятельный класс. Не определено, присваивается ли тип возвращаемого значения.

Член-функция operator()

template< class... Args >
constexpr auto operator()( Args&&... args ) const
    noexcept(/* see below */)
-> decltype(
    !std::declval<std::invoke_result_t<decltype((ConstFn)), Args...>>());
(с C++26)

Экспрессивно эквивалентно !std::invoke(ConstFn, std::forward<Args>(args)...).

Исключения

1) Не бросает исключений, если не брошено исключение при построении fd.

Возможная реализация

(1) not_fn
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)};
}
(2) not_fn
namespace detail
{
    template<auto ConstFn>
    struct stateless_not_fn
    {
        template<class... Args>
        constexpr auto operator()(Args&&... args) const
            noexcept(noexcept(!std::invoke(ConstFn, std::forward<Args>(args)...)))
            -> decltype(!std::invoke(ConstFn, std::forward<Args>(args)...))
        {
            return !std::invoke(ConstFn, std::forward<Args>(args)...);
        }
    };
}
 
template<auto ConstFn>
constexpr detail::stateless_not_fn<ConstFn> not_fn() noexcept
{
    if constexpr (std::is_pointer_v<decltype(ConstFn)> ||
                  std::is_member_pointer_v<decltype(ConstFn)>)
        static_assert(ConstFn != nullptr);
 
    return {};
}

Примечания

std::not_fn предназначен для замены отрицаний std::not1 и std::not2 эпохи C++03.

Макрос проверки возможности использования функции Значение Стандарт Функция
__cpp_lib_not_fn 201603L (C++17) std::not_fn(), (1)
202306L (C++26) Разрешение передачи вызываемых объектов в качестве параметров шаблона нетипа std::not_fn, (2)

Пример

#include <cassert>
#include <functional>
 
bool is_same(int a, int b) noexcept
{
    return a == b;
}
 
struct S
{
    int val;
    bool is_same(int arg) const noexcept { return val == arg; }
};
 
int main()
{
    // Using with a free function:
    auto is_differ = std::not_fn(is_same);
    assert(is_differ(8, 8) == false); // equivalent to: !is_same(8, 8) == false
    assert(is_differ(6, 9) == true); // equivalent to: !is_same(8, 0) == true
 
    // Using with a member function:
    auto member_differ = std::not_fn(&S::is_same);
    assert(member_differ(S{3}, 3) == false); //: S tmp{6}; !tmp.is_same(6) == false
 
    // Noexcept-specification is preserved:
    static_assert(noexcept(is_differ) == noexcept(is_same));
    static_assert(noexcept(member_differ) == noexcept(&S::is_same));
 
    // Using with a function object:
    auto same = [](int a, int b) { return a == b; };
    auto differ = std::not_fn(same);
    assert(differ(1, 2) == true); //: !same(1, 2) == true
    assert(differ(2, 2) == false); //: !same(2, 2) == false
 
#if __cpp_lib_not_fn >= 202306L
    auto is_differ_cpp26 = std::not_fn<is_same>();
    assert(is_differ_cpp26(8, 8) == false);
    assert(is_differ_cpp26(6, 9) == true);
 
    auto member_differ_cpp26 = std::not_fn<&S::is_same>();
    assert(member_differ_cpp26(S{3}, 3) == false);
 
    auto differ_cpp26 = std::not_fn<same>();
    static_assert(differ_cpp26(1, 2) == true);
    static_assert(differ_cpp26(2, 2) == false);
#endif
}

См. также

not1
(устарело в C++17)(удалено в C++20)
создаёт пользовательский std::unary_negate объект
(шаблон функции)
not2
(устарело в C++17)(удалено в C++20)
создаёт пользовательский std::binary_negate объект
(шаблон функции)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/utility/functional/not_fn

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API