std::invoke
From cppreference.com
< cpp | utility | functional
Defined in header
<functional>
|
||
template< class F, class... ArgTypes>
std::result_of_t<F&&(ArgTypes&&...)> invoke(F&& f, ArgTypes&&... args); |
(since C++17) | |
Invoke the Callable
object f
with the parameters args
. As by INVOKE(std::forward<F>(f), std::forward<Args>(args)...).
where INVOKE(f, t1, t2, ..., tN) is defined as follows:
- if
f
is a pointer to member function of classT
:
-
- If std::is_base_of<T, std::decay_t<decltype(t1)>>::value is true, then INVOKE(f, t1, t2, ..., tN) is equivalent to (t1.*f)(t2, ..., tN)
- otherwise, if std::decay_t<decltype(t1)> is a specialization of std::reference_wrapper, then INVOKE(f, t1, t2, ..., tN) is equivalent to (t1.get().*f)(t2, ..., tN)
- otherwise, if
t1
does not satisfy the previous items, then INVOKE(f, t1, t2, ..., tN) is equivalent to ((*t1).*f)(t2, ..., tN).
- otherwise, if N == 1 and
f
is a pointer to data member of classT
:
-
- If std::is_base_of<T, std::decay_t<decltype(t1)>>::value is true, then INVOKE(f, t1) is equivalent to t1.*f
- otherwise, if std::decay_t<decltype(t1)> is a specialization of std::reference_wrapper, then INVOKE(f, t1) is equivalent to t1.get().*f
- otherwise, if
t1
does not satisfy the previous items, then INVOKE(f, t1) is equivalent to (*t1).*f
- otherwise, INVOKE(f, t1, t2, ..., tN) is equivalent to f(t1, t2, ..., tN) (that is,
f
is aFunctionObject
)
Contents |
[edit] Parameters
f | - | Callable object to be invoked
|
args | - | arguments to pass to f
|
[edit] Possible implementation
namespace detail { template <class T> struct is_reference_wrapper : std::false_type {}; template <class U> struct is_reference_wrapper<std::reference_wrapper<U>> : std::true_type {}; template <class T> constexpr bool is_reference_wrapper_v = is_reference_wrapper<T>::value; template <class Base, class T, class Derived, class... Args> auto INVOKE(T Base::*pmf, Derived&& ref, Args&&... args) noexcept(noexcept((std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...))) -> std::enable_if_t<std::is_function_v<T> && std::is_base_of_v<Base, std::decay_t<Derived>>, decltype((std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...))> { return (std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...); } template <class Base, class T, class RefWrap, class... Args> auto INVOKE(T Base::*pmf, RefWrap&& ref, Args&&... args) noexcept(noexcept((ref.get().*pmf)(std::forward<Args>(args)...))) -> std::enable_if_t<std::is_function_v<T> && is_reference_wrapper_v<std::decay_t<RefWrap>>, decltype((ref.get().*pmf)(std::forward<Args>(args)...))> { return (ref.get().*pmf)(std::forward<Args>(args)...); } template <class Base, class T, class Pointer, class... Args> auto INVOKE(T Base::*pmf, Pointer&& ptr, Args&&... args) noexcept(noexcept(((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...))) -> std::enable_if_t<std::is_function_v<T> && !is_reference_wrapper_v<std::decay_t<Pointer>> && !std::is_base_of_v<Base, std::decay_t<Pointer>>, decltype(((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...))> { return ((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...); } template <class Base, class T, class Derived> auto INVOKE(T Base::*pmd, Derived&& ref) noexcept(noexcept(std::forward<Derived>(ref).*pmd)) -> std::enable_if_t<!std::is_function_v<T> && std::is_base_of_v<Base, std::decay_t<Derived>>, decltype(std::forward<Derived>(ref).*pmd)> { return std::forward<Derived>(ref).*pmd; } template <class Base, class T, class RefWrap> auto INVOKE(T Base::*pmd, RefWrap&& ref) noexcept(noexcept(ref.get().*pmd)) -> std::enable_if_t<!std::is_function_v<T> && is_reference_wrapper_v<std::decay_t<RefWrap>>, decltype(ref.get().*pmd)> { return ref.get().*pmd; } template <class Base, class T, class Pointer> auto INVOKE(T Base::*pmd, Pointer&& ptr) noexcept(noexcept((*std::forward<Pointer>(ptr)).*pmd)) -> std::enable_if_t<!std::is_function_v<T> && !is_reference_wrapper_v<std::decay_t<Pointer>> && !std::is_base_of_v<Base, std::decay_t<Pointer>>, decltype((*std::forward<Pointer>(ptr)).*pmd)> { return (*std::forward<Pointer>(ptr)).*pmd; } template <class F, class... Args> auto INVOKE(F&& f, Args&&... args) noexcept(noexcept(std::forward<F>(f)(std::forward<Args>(args)...))) -> std::enable_if_t<!std::is_member_pointer_v<std::decay_t<F>>, decltype(std::forward<F>(f)(std::forward<Args>(args)...))> { return std::forward<F>(f)(std::forward<Args>(args)...); } } // namespace detail template< class F, class... ArgTypes > auto invoke(F&& f, ArgTypes&&... args) // exception specification for QoI noexcept(noexcept(detail::INVOKE(std::forward<F>(f), std::forward<ArgTypes>(args)...))) -> decltype(detail::INVOKE(std::forward<F>(f), std::forward<ArgTypes>(args)...)) { return detail::INVOKE(std::forward<F>(f), std::forward<ArgTypes>(args)...); }
[edit] Example
Implement the basic functionality of std::mem_fn.
Run this code
#include <functional> template< class PM > class mem_fn_t { PM p; public: mem_fn_t(PM p):p(p){} template<class... Args> decltype(auto) operator()(Args&&... args) { return std::invoke(p, std::forward<Args>(args)...); } }; template< class R, class T > auto mem_fn(R T::* pm){ mem_fn_t<R T::*> t {pm}; return t; }
[edit] See also
(C++11)
|
creates a function object out of a pointer to a member (function template) |
(C++11)
|
deduces the return type of a function call expression (class template) |
(C++17)
|
checks if a type can be invoked (as if by std::invoke) with the given argument types (class template) |