Search code examples
c++c++17forwarding-referenceresult-of

Correct way of using invoke_result?


On cppreference, it is written that the correct way of using std::result_of is:

template<class F, class... Args>
std::result_of_t<F&&(Args&&...)> 
// instead of std::result_of_t<F(Args...)>, which is wrong
  my_invoke(F&& f, Args&&... args) { 
    /* implementation */
}

I was wondering how std::invoke_result_t should be used: invoke_result_t:

template<class F, class... Args> 
std::invoke_result_t<F&&, Args&&...> my_invoke(F&& f, Args&&... args);

Or:

template<class F, class... Args> 
std::invoke_result_t<F, Args...> my_invoke(F&& f, Args&&... args);

Solution

  • invoke_result is defined in terms of declval:

    If the expression INVOKE(declval<Fn>(), declval<ArgTypes>()...) is well-formed when treated as an unevaluated operand, the member typedef type names the type decltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...)); otherwise, there shall be no member type.

    and declval is specified as:

    template<class T> add_rvalue_reference_t<T> declval() noexcept;
    

    So there's no difference between std::invoke_result_t<F&&, Args&&...> and std::invoke_result_t<F, Args...>. Well, the latter is 4 characters shorter, but they mean exactly the same thing (since neither F nor Args... could be void).