Search code examples
c++typesreturnc++14auto

C++14 'auto' is able to get function return type, do we still need std::result_of<>?


Seems C++14 auto keyword can be used to appear at the location of function definition as to indicate the return type. In this case, is std::result_of still needed? Isn't it obsolete now?


Solution

  • Yes, absolutely.

    1. Sometimes you want the return type, but not as the result of the function. Let's say I have a vector<X> and I want to apply a function to each element and return the result. This operation is called map or fmap, and we might implement the signature thusly:

      template <class T, class F,
          class U = std::decay_t<std::result_of_t<F&(T const&)>>>
      std::vector<U> map(std::vector<T> const&, F );
      

      You could make the return type auto, but regardless, you need to compute that type U and auto won't give it to you. Any time you want the result of a function call that won't necessarily be the return type, auto won't cut it.

    2. SFINAE. Consider the difference between:

      template <class F>
      decltype(auto) foo(F f) { return f(0); }
      template <class F>
      std::result_of_t<F&(int)> bar(F f) { return f(0); }
      

      If F is not invokable with an int, then instantiating foo() is a hard compile error but bar() would simply be removed from the overload set. This can be very valuable in generic code, as you can test expressions for well-formedness.

    3. Annotation. auto tells you nothing about the function return type. If the function is returning the result of invoking one callable with some args, std::result_of_t<F(A, B)> in of itself tells me what that function is doing. auto tells me nothing.


    Really a better question may be... why do we need std::result_of if we have decltype. Those seem more closely related. After all, I can do decltype(x+1), how would I express that in terms of result_of?! decltype is clearly better. Well, it turns out there are some slight differences between the two even when it comes to determining the result of a function invocation.