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

std::invoke, std::invoke_r

Материал из cppreference.com
 
 
Библиотека утилит
Языковая поддержка
Поддержка типов (базовые типы, 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)

Отрицатели
(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*)
 
<tbody> </tbody> <tbody class="t-dcl-rev t-dcl-rev-num "> </tbody><tbody> </tbody>
Определено в заголовочном файле <functional>
(1)
template< class F, class... Args > std::invoke_result_t<F, Args...> invoke( F&& f, Args&&... args ) noexcept(/* смотрите ниже */);
(начиная с C++17)
(до C++20)
template< class F, class... Args > constexpr std::invoke_result_t<F, Args...> invoke( F&& f, Args&&... args ) noexcept(/* смотрите ниже */);
(начиная с C++20)
template< class R, class F, class... Args > constexpr R invoke_r( F&& f, Args&&... args ) noexcept(/* смотрите ниже */);
(2) (начиная с C++23)
1) Вызвать объект Callable f с параметрами args, как INVOKE(std::forward<F>(f), std::forward<Args>(args)...). Эта перегрузка участвует в разрешении перегрузки, только если std::is_invocable_v<F, Args...> равно true.
2) Вызвать объект Callable f с параметрами args, как INVOKE<R>(std::forward<F>(f), std::forward<Args>(args)...). Эта перегрузка участвует в разрешении перегрузки, только если std::is_invocable_r_v<R, F, Args...> равно true.

Параметры

f Callable объект для вызова
args аргументы для передачи f

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

1) Значение, возвращаемое f.
2) Значение, возвращаемое f, неявно преобразуется в R, если R не равно void. Иначе ничего.

Исключения

1)
спецификация noexcept:  
noexcept(std::is_nothrow_invocable_v<F, Args...>)
2)
спецификация noexcept:  
noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>)

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

invoke
namespace detail
{
    template<class>
    constexpr bool is_reference_wrapper_v = false;
    template<class U>
    constexpr bool is_reference_wrapper_v<std::reference_wrapper<U>> = true;
    
    template<class C, class Pointed, class T1, class... Args>
    constexpr decltype(auto) invoke_memptr(Pointed C::* f, T1&& t1, Args&&... args)
    {
        if constexpr (std::is_function_v<Pointed>)
        {
            if constexpr (std::is_base_of_v<C, std::decay_t<T1>>)
                return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
            else if constexpr (is_reference_wrapper_v<std::decay_t<T1>>)
                return (t1.get().*f)(std::forward<Args>(args)...);
            else
                return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
        }
        else
        {
            static_assert(std::is_object_v<Pointed> && sizeof...(args) == 0);
            if constexpr (std::is_base_of_v<C, std::decay_t<T1>>)
                return std::forward<T1>(t1).*f;
            else if constexpr (is_reference_wrapper_v<std::decay_t<T1>>)
                return t1.get().*f;
            else
                return (*std::forward<T1>(t1)).*f;
        }
    }
} // пространство имён detail

template<class F, class... Args>
constexpr std::invoke_result_t<F, Args...> invoke(F&& f, Args&&... args)
    noexcept(std::is_nothrow_invocable_v<F, Args...>)
{
    if constexpr (std::is_member_pointer_v<std::decay_t<F>>)
        return detail::invoke_memptr(f, std::forward<Args>(args)...);
    else
        return std::forward<F>(f)(std::forward<Args>(args)...);
}
invoke_r
template<class R, class F, class... Args>
    requires std::is_invocable_r_v<R, F, Args...>
constexpr R invoke_r(F&& f, Args&&... args)
    noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>)
{
    if constexpr (std::is_void_v<R>)
        std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
    else
        return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
}

Примечание

Макрос тест функциональности Значение Стандарт Комментарий
__cpp_lib_invoke 201411L (C++17) std::invoke
__cpp_lib_invoke_r 202106L (C++23) std::invoke_r

Пример

#include <functional>
#include <iostream>
#include <type_traits>

struct Foo
{
    Foo(int num) : num_(num) {}
    void print_add(int i) const { std::cout << num_+i << '\n'; }
    int num_;
};

void print_num(int i)
{
    std::cout << i << '\n';
}

struct PrintNum
{
    void operator()(int i) const
    {
        std::cout << i << '\n';
    }
};

int main()
{
    // вызвать свободную функцию
    std::invoke(print_num, -9);

    // вызвать лямбду
    std::invoke([]() { print_num(42); });

    // вызвать функцию-элемент
    const Foo foo(314159);
    std::invoke(&Foo::print_add, foo, 1);
   
    // вызвать (получить доступ к) элемент данных
    std::cout << "num_: " << std::invoke(&Foo::num_, foo) << '\n';

    // вызвать функциональный объект
    std::invoke(PrintNum(), 18);

#   if defined(__cpp_lib_invoke_r)
    auto add = [](int x, int y) { return x + y; };
    auto ret = std::invoke_r<float>(add, 11, 22);
    static_assert(std::is_same<decltype(ret), float>());
    std::cout << ret << '\n';
    std::invoke_r<void>(print_num, 44);
#   endif
}

Возможный вывод:

-9
42
314160
num_: 314159
18
33
44

Смотрите также

(C++11)
создаёт объект функцию из указателя на элемент
(шаблон функции) [править]
(C++11)(удалено в C++20)(C++17)
выводит тип результата вызова вызываемого объекта с набором аргументов
(шаблон класса) [править]
проверяет, может ли тип быть вызван (как если бы std::invoke) с заданными типами аргументов
(шаблон класса) [править]
(C++17)
вызывает функцию с кортежем аргументов
(шаблон функции) [править]