Увидел сейчас, что в 17ом стандарте появилась новая шаблонная функция std::invoke
. Очень сильно обрадовался, т.к. подумал, что это такой же invoke
как в .NET, но поискав информацию о нём, так до конца и не понял, зачем он нужен. Я так понял, что он делает вызов функторов и лямбд, но чем это отличается от их прямого вызова? Может ли std::invoke
делать этот вызов в определённом потоке, как это умеет делать его собрат из .NET?
std::invoke
нужен чтобы унифицированным образом вызвать функторы (в т.ч. лямбды), указатели на функции и указатели на функции-члены классов.
Последние имеют специфический синтаксис вызова не совпадающий с синтаксисом обычных функторов:
(obj->*mem_fn_ptr)( args... );
Если вы пишите функцию типа std::async
, и вам нужно реализовать поддержку всех callable объектов, то проще передать их одним пакетом в invoke
, чем писать отдельную шаблонную реализацию для каждого случая. Такой синтаксический сахар.
Аналога .NET invoke
в стандарте нет, потому что нет циклов обработки сообщений, и соответственно, "послать задачу в поток" невозможно. Воспользуйтесь std::async
, либо std::thread
, если нужно просто асинхронное выполнение, либо функциями WinAPI, либо функциями вашей оконной библиотеки (Qt, wxWidgets...), либо организуйте цикл обработки сообщений "вручную", и запихивайте упакованную задачу в соответствующую очередь.
Смысл std::invoke
в вызове обычных методов и нестатических методов класса в единообразной манере. Это прежде всего полезно при написании шаблонов. Вот например компактный шаблон функции, оборачивающий вызов другой функции:
template<typename F, typename V1, typename V2> auto
foo(F f, V1 v1, V2 v2) -> void
{
::std::invoke(f, v1, v2);
}
Пример использования:
inline auto
bar(int v1, int v2) -> void
{
::std::cout << v1 << " " << v2 << ::std::endl;
}
class Bar
{
private: int m_v;
public: explicit
Bar(int v): m_v{v} {}
public: auto
bar(int v2) -> void
{
::std::cout << m_v << " " << v2 << ::std::endl;
}
};
int
main()
{
int v1{12};
int v2{23};
foo(&bar, v1, v2); // вызов обычного метода
Bar b{12};
foo(&Bar::bar, b, v2); // вызов нестатического метода класса по ссылке
foo(&Bar::bar, &b, v2); // вызов нестатического метода класса по указателю
}
Без использования ::std::invoke
пришлось бы самостоятельно реализовывать варианты для вызова нестатических методов класса:
template<typename F, typename V1, typename V2> auto
foo(F f, V1 v1, V2 v2) -> ::std::enable_if_t
<
not ::std::is_member_function_pointer_v<F>
>
{
f(v1, v2);
}
template<typename F, typename V1, typename V2> auto
foo(F f, V1 v1, V2 v2) -> ::std::enable_if_t
<
::std::is_member_function_pointer_v<F> and not ::std::is_pointer_v<V1>
>
{
(v1.*f)(v2);
}
template<typename F, typename V1, typename V2> auto
foo(F f, V1 v1, V2 v2) -> ::std::enable_if_t
<
::std::is_member_function_pointer_v<F> and ::std::is_pointer_v<V1>
>
{
(v1->*f)(v2);
}
От прямого вызова это отличается тем, что не всё что умеет вызывать std::invoke
, можно вызвать напрямую.
Упрощенно говоря, вызов std::invoke(f, arg0, args...)
пытается сделать один из следующих вызовов:
(arg0.*f)(args...);
(arg0.get().*f)(args...);
((*arg0).*f)(args...);
arg0.*f
arg0.get().*f;
(*arg0).*f;
f(arg0, args...);
Использование std::invoke
требуется в тех случаях, когда вы пишите обобщенный код, способный работать с любым переданным Callable-объектом.
Что же до вызова функции в фоновом потоке - то для этих целей придумана функция std::async
.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Какие существуют виды рекламных бордов и как выбрать подходящий?
Мне надо обрабатывать отображение миниатюр фотографий в отдельном потоке, иначе код очень долго обрабатываетсяУ меня есть в основном классе...
Использую cron и quartzНужно реализовать следующие: Администратор назначает на конкретную дату некое задание, которое обновляет базу данных
У меня есть серверное приложение на JavaВозникла необходимость запускать пользовательские скрипты, для этого я решил использовать Python, так...