227

I came across the following code:

template <typename T, typename T1> auto compose(T a, T1 b) -> decltype(a + b) {
   return a+b;
}

There is one thing I cannot understand:

Where could I find out what the arrow operator (->) means in the function heading?

I guess purely logically, that the -> operator determines a type, that auto will be deduced to, but I want to get this straight. I can't find any information.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
user1234567
  • 3,991
  • 3
  • 19
  • 25
  • 3
    It's part of the trailing return type syntax. See http://stackoverflow.com/a/4113390/962089 – chris Mar 19 '14 at 18:24
  • 3
    It is not an operator but a part of the syntax. – SwiftMango Mar 19 '14 at 18:30
  • 2
    In answer to "where can I read?", the C++ Spec is most authoritative. Lacking funds or desire to spend $$, the last working draft is often close enough and no-cost. These specs are highly techo-speak, so lacking familiarity with reading ISO specs, try cplusplus.com or cppreference.com or other such sites which are not authoritative, but are usually very accurate. Note: the trailing return type may be omitted beginning with C++14. – Les Sep 23 '15 at 13:56

3 Answers3

367

In C++11, there are two syntaxes for function declaration:

    return-type identifier ( argument-declarations... )

and

    auto identifier ( argument-declarations... ) -> return_type

They are equivalent. Now when they are equivalent, why do you ever want to use the latter? Well, C++11 introduced this cool decltype thing that lets you describe type of an expression. So you might want to derive the return type from the argument types. So you try:

template <typename T1, typename T2>
decltype(a + b) compose(T1 a, T2 b);

and the compiler will tell you that it does not know what a and b are in the decltype argument. That is because they are only declared by the argument list.

You could easily work around the problem by using declval and the template parameters that are already declared. Like:

template <typename T1, typename T2>
decltype(std::declval<T1>() + std::declval<T2>())
compose(T1 a, T2 b);

except it's getting really verbose now. So the alternate declaration syntax was proposed and implemented and now you can write

template <typename T1, typename T2>
auto compose(T1 a, T2 b) -> decltype(a + b);

and it's less verbose and the scoping rules didn't need to change.


C++14 update: C++14 also permits just

    auto identifier ( argument-declarations... )

as long as the function is fully defined before use and all return statements deduce to the same type. The -> syntax remains useful for public functions (declared in the header) if you want to hide the body in the source file. Somewhat obviously that can't be done with templates, but there are some concrete types (usually derived via template metaprogramming) that are hard to write otherwise.

Nathan Ernst
  • 4,540
  • 25
  • 38
Jan Hudec
  • 73,652
  • 13
  • 125
  • 172
  • 8
    very good, neat and informative reply @Jan Hudec. Thumps up. Is there something changed in `C++14` as I use `auto` for `return` type in such function without the need for the `-> decltype(a + b)` part. Is it redundant by now or does it have other cases where it still should be used? or is it a compiler specific extension? – Shadi Apr 11 '17 at 12:04
  • 1
    @Shadi, C++14 includes [N3638](https://isocpp.org/files/papers/N3638.html), which allows deduction of the return type declared as `auto`, without the `->` notation, as long as the function is fully defined before use and all `return` statements deduce to the same type. The `->` notation is still useful if you want to use deduction for public function while hiding the body in the source file. – Jan Hudec Apr 11 '17 at 17:19
  • Do you mean **private** functions? I don't see why a public function would not show its return type. For private functions it would make sense if they used implementation defined structures (now can be isolated to .cpp) – Kostas Nov 06 '20 at 18:33
  • 2
    @Kostas, I did mean what I wrote. With private function you can generally ensure it is defined before use, so you can use just `auto` (from C++14). It is *public* function that is usually used from places where it is not *defined* (only declared), so it still needs to use the `->` notation. Of course if you can name the return type, you just do, but this whole discussion is about the case where you want to deduce it, which happens when you *can't* (easily) *name the type.* – Jan Hudec Nov 06 '20 at 21:19
  • The use case given by @chalktalk is also a good case for using -> when defining out of class member functions. It removes the need to provide scope resolution prefix. This is even more useful when defining out of class member functions of a class template. – Shriram V Jul 15 '22 at 09:26
  • 1
    Also `->` is the only way for explicitly specifying a return type in lambdas. – Shriram V Jul 15 '22 at 09:47
34

In plain english it tells that the return type is the inferred type of the sum of a and b.

Niklas B.
  • 92,950
  • 18
  • 194
  • 224
murrekatt
  • 5,961
  • 5
  • 39
  • 63
4

Aside from decltype and declval uses, you can define class member functions using return types defined within the class without needing to provide the Class:: scope resolution prefix a second time.

Example:

class SomeLongClassname
{
public:
  typedef std::shared_ptr<Node> PNode;

  PNode make_node ();
};

Choose:

SomeLongClassname::PNode SomeLongClassname::make_node () { ... }

or

auto SomeLongClassname::make_node () -> PNode { ... }

The second form is sometimes more legible.

ChalkTalk
  • 604
  • 6
  • 10
  • Had SomeLongClassname been a template, `template typename SomeLongClassname::PNode SomeLongClassname::make_node() { ... }` vs just simplifying to `template auto SomeLongClassname::make_node() -> PNode { ... }` – Shriram V Jul 15 '22 at 09:20