Search code examples
c++c++17c++20trailing-return-typedecltype-auto

Does decltype(auto) make trailing return type obsolete?


There have been many, many, many questions and answers regarding the trailing return type, auto return type deduction and the very useful decltype(auto). But I failed to find an answer to whether the trailing return type is needed at all since we have decltype(auto). Are there cases that the trailing return type solves, where decltype(auto) either cannot be used or doesn't work (gives unexpected / incorrect results) and the trailing return type was needed in the first place?


Solution

  • decltype(auto) (and more generally deduced return type) and trailing return type are orthogonal features.

    You can have:

    • decltype(auto) f() {}
    • auto f() -> decltype(auto) {}

    Trailing return type

    trailing return type is fine especially to have access to context we don't have before the function name

    • as for template:

      template <typename T>
      auto f(T x) -> decltype(bar(x));
      

      versus

      template <typename T>
      decltype(bar(std::declval<T&>())) f(T x);
      
    • or for dependent name in class:

      auto C::begin() -> iterator;
      

      versus

      C::iterator C::begin();
      

    The only place where it is required is for lambda (if you have/want to specify return type explicitly):

    • []() -> some_type {/*...*/}
    • []() -> auto {/*...*/} (which is equivalent to []() {/*...*/})
    • []() -> decltype(auto) {/*...*/}

    Case when we have to defining return type of lambda is when it should return reference type.

    Deduced return type

    Done with decltype(auto) and auto.

    decltype(auto) and auto deduction type differs, mostly as T&& and T.

    Deduced return type requires definition of the body.

    They also doesn't allow SFINAE, as there are no substitution.