Search code examples
c++c++17c++14metaprogrammingc++20

How to use std::invoke_result_t in c++17 or 20 instead of std::result_of_t in c++14?


when I use std::result_of_t in c++14 it's doing as i wish:

void just_simple()
{
    std::cout << "【4】: in func return nothing. " << std::endl;
}

template<typename Callback, typename... Args>
auto InTemplate_Call(Callback&& bc, Args&&... args)
{
    typedef typename std::result_of_t<std::decay_t<Callback>(std::decay_t<Args>...)> ReturnType;

    //typedef typename std::invoke_result_t<std::decay_t<Callback>(std::decay_t<Args>...)> ReturnType;

    if (typeid(ReturnType) == typeid(void))
    {
        std::cout << "get a void type" << std::endl;
    }

    return rtDeduction<ReturnType>::type();
}

int main(){
    InTemplate_Call(just_simple);

    return 0;
}

The ReturnType is just void.

But It's not work in c++17 or 20:

template<typename Callback, typename... Args>
auto InTemplate_Call(Callback&& bc, Args&&... args)
{
    //typedef typename std::result_of_t<std::decay_t<Callback>(std::decay_t<Args>...)> ReturnType;

    typedef typename std::invoke_result_t<std::decay_t<Callback>(std::decay_t<Args>...)> ReturnType;

    if (typeid(ReturnType) == typeid(void))
    {
        std::cout << "get a void type" << std::endl;
    }

    return rtDeduction<ReturnType>::type();
}

The ReturnType is not void anymore!

Is there anything I made mistake?


Solution

  • The difference between invoke_result and result_of is that the former accepts the callable type and arguments type, but your std::decay_t<Callback>(std::decay_t<Args>...) is just a function type that returns a std::decay_t<Callback>.

    The following shows the differences:

    #include <functional>
    
    void just_simple() {}
    
    template<typename Callback>
    void foo(Callback&&)
    {
      static_assert(std::is_same_v<std::invoke_result_t<Callback()>, Callback>);
      static_assert(std::is_same_v<std::invoke_result_t<Callback  >, void>);
    }
    
    int main() {
      foo(just_simple);
    }
    

    You should do this:

    typedef typename std::invoke_result_t<
      std::decay_t<Callback>, 
      std::decay_t<Args>...> ReturnType;