std::invoke

From cppreference.com
< cpp‎ | utility‎ | functional
 
 
Utilities library
Type support (basic types, RTTI, type traits)
Dynamic memory management
Error handling
Program utilities
Variadic functions
Date and time
Function objects
(C++11)
Relational operators
Optional and any
(C++17)
(C++17)
Pairs and tuples
(C++11)
(C++17)
Swap, forward and move
(C++14)
(C++11)
(C++11)
Type operations
(C++11)
(C++17)
 
Function objects
Function wrappers
(C++11)
(C++11)
invoke
(C++17)
Bind
(C++11)
(C++11)
(C++11)
Reference wrappers
(C++11)(C++11)
Operator wrappers
Negators
(deprecated)
(deprecated)
(deprecated)
(deprecated)
Searchers
Old binders and adaptors
(until C++17)
(until C++17)
(until C++17)
(until C++17)
(until C++17)(until C++17)(until C++17)(until C++17)
(until C++17)
(until C++17)(until C++17)(until C++17)(until C++17)
(until C++17)(until C++17)
(until C++17)(until C++17)
 
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 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).
  • 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 a FunctionObject)


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.

#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)
checks if a type can be invoked (as if by std::invoke) with the given argument types
(class template)