Определите INVOKE(f, t1, t2, ..., tN) следующее:
(t1.*f)(t2, ..., tN) when f - указатель на функцию-член класса T и is_base_of_v<T, decay_t<decltype(t1)>> is true;
(t1.get().*f)(t2, ..., tN) when f - указатель на функцию-член класса T и decay_t<decltype(t1)> является специализацией reference_wrapper;
((*t1).*f)(t2, ..., tN) when f является указателем на функцию-член класса T и t1 не удовлетворяет двум предыдущим элементам;
t1.*f когда N == 1 и f является указателем на член данных класса T и is_base_of_v<T, decay_t<decltype(t1)>> является true;
t1.get().*f когда N == 1 и f является указателем на член данных класса T и decay_t<decltype(t1)> является специализацией reference_wrapper;
(*t1).*f когда N == 1 и f является указателем на член данных класса T и t1 не удовлетворяет двум предыдущим элементам;
f(t1, t2, ..., tN) во всех остальных случаях.
Определите INVOKE<R>(f, t1, t2, ..., tN) как static_cast<void>(INVOKE(f, t1, t2, ..., tN)) если бы R есть cv void, иначе INVOKE(f, t1, t2, ..., tN) неявно преобразовать в R.
Каждый call wrapper должен быть MoveConstructible. A forwarding call wrapper - это оболочка вызова, которая может быть вызвана с произвольным списком аргументов и доставляет аргументы обернутому вызываемому объекту в виде ссылок. Этот шаг пересылки должен гарантировать, что аргументы rvalue доставляются как ссылки rvalue, а аргументы lvalue доставляются как ссылки lvalue. A simple call wrapper - это оболочка переадресации вызовов, которая есть CopyConstructible и, CopyAssignable чей конструктор копирования, конструктор перемещения и оператор присваивания не генерируют исключения. [ Note: В типичной реализации оболочки переадресации вызовов имеют перегруженный оператор вызова функции вида
template<class... UnBoundArgs>
R operator()(UnBoundArgs&&... unbound_args) cv-qual;
— end note ]