Пространства имён
Варианты
Действия

std::not_fn

Материал из cppreference.com
< cpp‎ | utility‎ | functional
 
 
Библиотека утилит
Языковая поддержка
Поддержка типов (базовые типы, RTTI)
Макросы тестирования функциональности библиотеки (C++20)    
Управление динамической памятью
Программные утилиты
Поддержка сопрограмм (C++20)
Вариативные функции
Трёхстороннее сравнение (C++20)
(C++20)
(C++20)(C++20)(C++20)(C++20)(C++20)(C++20)
Общие утилиты
Дата и время
Функциональные объекты
Библиотека форматирования (C++20)
(C++11)
Операторы отношения (устарело в C++20)
Целочисленные функции сравнения
(C++20)(C++20)(C++20)    
(C++20)
Операции обмена и типа
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
Общие лексические типы
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)
Элементарные преобразования строк
(C++17)
(C++17)
 
Объекты функции
Функции обёртки
(C++11)
(C++11)
Применение частичных функций
(C++20)(C++23)
(C++11)
Вызов функции
(C++17)(C++23)
Объект идентичности функции
(C++20)
Обёртки ссылок
(C++11)(C++11)
Прозрачные обёртки операторов
(C++14)
(C++14)
(C++14)
(C++14)  
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)

Отрицатели
not_fn
(C++17)
Искатели
Ограниченные компараторы
Старые привязки и адаптеры
(до C++17*)
(до C++17*)
(до C++17*)
(до C++17*)
(до C++17*)(до C++17*)(до C++17*)(до C++17*)
(до C++20*)
(до C++20*)
(до C++17*)(до C++17*)
(до C++17*)(до C++17*)

(до C++17*)
(до C++17*)(до C++17*)(до C++17*)(до C++17*)
(до C++20*)
(до C++20*)
 
Определено в заголовочном файле <functional>
template< class F >
/* неуказано */ not_fn( F&& f );
(1) (начиная с C++17)
(constexpr начиная с C++20)
template< auto ConstFn >
constexpr /* неуказано */ 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(/*смотрите ниже*/)
-> decltype(
    !std::declval<std::invoke_result_t<std::decay_t<F>&, Args...>>());
template<class... Args> constexpr auto operator()(Args&&... args) const&
   noexcept(/*смотрите ниже*/)
-> 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(/*смотрите ниже*/)
-> decltype(
    !std::declval<std::invoke_result_t<std::decay_t<F>, Args...>>());
template<class... Args> constexpr auto operator()(Args&&... args) const&&
   noexcept(/*смотрите ниже*/)
-> 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)...);

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

(начиная с C++17)
(до C++20)

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

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

std::not_fn возвращаемый тип без сохранения состояния

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

Функция-элемент operator()

template< class... Args >

constexpr auto operator()( Args&&... args ) const
    noexcept(/* смотрите ниже */)
-> decltype(

    !std::declval<std::invoke_result_t<decltype((ConstFn)), Args...>>());
(начиная с C++26)

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

[править] Исключения

Исключения не генерируются, если их не генерирует создание 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)...);
        }
 
        // Удалённые перегрузки необходимы начиная с C++20 для предотвращения
        // выбора неэквивалентной, но правильно сформированной перегрузки.
 
        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()
{
    // Использование с свободной функцией:
    auto is_differ = std::not_fn(is_same);
    assert(is_differ(8, 8) == false); // эквивалентно: !is_same(8, 8) == false
    assert(is_differ(6, 9) == true); // эквивалентно: !is_same(8, 0) == true
 
    // Использование с функцией-элементом:
    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 спецификация сохраняется:
    static_assert(noexcept(is_differ) == noexcept(is_same));
    static_assert(noexcept(member_differ) == noexcept(&S::is_same));
 
    // Использование с функциональным объектом:
    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
}

[править] Смотрите также

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