<html>
<style>
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  strong { color: #2020ff }
</style>
<title>Return type deduction for normal functions</title>
<body>
Jason Merrill
<br>2013-04-17
<br>Revision 5
<br>N3638

<h2><b>Return type deduction for normal functions</b></h2>

<h3>Introduction</h3>

Any C++ user introduced to the C++11 features of <tt>auto</tt>, lambdas,
and trailing return types immediately wonders why they can't just
write <tt>auto</tt> on their function declaration and have the return type
deduced.  This functionality was proposed previously in
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2954.html">N2954</a>,
but dropped from C++11 due to time constraints, as the drafting didn't
address various questions and concerns that the Core WG had.  I have now
implemented this functionality in GCC, and propose to add it to C++14.  I
discuss some of the less obvious aspects of the semantics below.

<p/>This proposal also resolves core DRs 975 (lambda return type deduction
from multiple return statements), 1048 (inconsistency between auto and
lambda return type deduction)<strong>, and 1588 (deducing cv-qualified auto)</strong>.

<h3>ChangeLog</h3>
Revision 2: N3386<br/>
Revision 3: N3582
<ul>
  <li>Add <tt>decltype(auto)</tt></li>
  <li>Allow <tt>auto</tt> in <i>trailing-return-type</i></li>
  <li>Prohibit deduction from an initializer-list</li>
</ul>
Revision 4:
<ul>
  <li>Prohibit <tt>virtual auto</tt></li>
  <li>Require <tt>decltype(auto)</tt> to stand alone</li>
  <li>Clarify explicit instantiation declaration</li>
</ul>
Revision 5: N3638
<ul>
  <li>Add friend and address overloading examples</li>
  <li>Resolve core issue 1588</li>
  <li>Clarify sfinae and instantiation time</li>
</ul>
Changes since N3582 are <strong>bold and blue</strong>.

<h3>Redeclaration</h3>

Allowing non-defining function declarations with auto return type is not
strictly necessary, but it is useful for coding styles
that prefer to define member functions outside the class:

<blockquote><pre>
struct A {
  auto f(); // forward declaration
};
auto A::f() { return 42; }
</pre></blockquote>

and if we allow it in that situation, it should be valid in other
situations as well.  Allowing it is also the more orthogonal choice; in
general, I believe that if combining two features can work, it should work.

<p/>The proposed wording allows non-defining declarations so long as all
declarations have the same declared type, without considering the deduced
type.

<blockquote><pre>
auto f(); // return type is unknown
auto f() { return 42; } // return type is int
auto f(); // redeclaration
int  f(); // error, declares a different function
</pre></blockquote>

And similarly for templates:

<blockquote><pre>
template &lt;class T> auto g(T t); // forward declaration
template &lt;class T> auto g(T t) { return t; } // return type is deduced at instantiation time
template &lt;class T> auto g(T t); // redeclaration
</pre></blockquote>

<p/>Of course, using such a function in an expression when only a forward
declaration has been seen is ill-formed:

<blockquote><pre>
auto f();    // return type is unknown
int i = f(); // error, return type of f is unknown
</pre></blockquote>

An explicit specialization or instantiation of an auto template must also
use auto.  An explicit specialization or instantiation of a non-auto
template must not use auto.

<blockquote><pre>
template &lt;class T> auto f(T t) { return t; } // #1
template auto f(int); // OK
template char f(char); // error, no matching template
template&lt;> auto f(double); // OK, forward declaration with unknown return type

template &lt;class T> T f(T t) { return t; } // OK, not functionally equivalent to #1
template char f(char); // OK, now there is a matching template
template auto f(float); // OK, matches #1
</pre></blockquote>

<h3>Multiple returns</h3>

<p/>The limitation on return type deduction to function bodies consisting
of a single return statement is inconvenient for lambdas (DR 975), but is
likely to be even more of an annoyance on normal functions.

<blockquote><pre>
auto iterate(int len) // error, body isn't "return expr;"
{
  for (int i = 0; i < len; ++i)
    if (search (i))
      return i;
  return -1;
}
</pre></blockquote>

Both return statements here return int, we can determine that perfectly
well.  The proposed wording allows this example, and resolves core issue
975.

<h3>Recursion</h3>

One important difference between lambdas and normal functions is that
normal functions can refer to themselves by name.  Of course, we can't
deduce the return type that way:

<blockquote><pre>
auto h() { return h(); } // error, return type of h is unknown
</pre></blockquote>

but once we have deduced a return type, there is no reason to prohibit recursion.

<blockquote><pre>
auto sum(int i) {
  if (i == 1)
    return i;          // return type deduced to int
  else
    return sum(i-1)+i; // ok to call it now
}
</pre></blockquote>

<h3>Instantiation</h3>

Like <tt>constexpr</tt> functions, it can be necessary to instantiate
an <tt>auto</tt> function template even if it is not odr-used.

<blockquote><pre>
template &lt;class T> auto f(T t) { return t; } // return type deduced at instantiation time
typedef decltype(f(1)) fint_t; // must instantiate f&lt;int> to deduce return type
</pre></blockquote>

<h3>SFINAE</h3>

Since the return type is deduced by instantiating the template, if the
instantiation is ill-formed, this causes an error rather than a
substitution failure.  This allows an <tt>auto</tt> function to return a
lambda, which is not possible using the
<tt>decltype(</tt><i>returned expression</i><tt>)</tt> pattern.

<h3>More general deduction</h3>

The declarator of a variable declared with <tt>auto</tt> is not limited in
the form of the declarator; the same should be true of a function with
deduced return type.  In particular, this is the only way to deduce return
by reference:

<blockquote><pre>
template &lt;class T> struct A { static T t; };
template &lt;class T> auto& f() { return A<T>::t; } // returns by reference
</pre></blockquote>

To allow this, we should use the same auto deduction rules for function and
lambda return type that we do for auto variables.  This would also resolve
core DR 1048, which objects to the difference in handling of cv-qualifiers
between auto deduction and lambda return type deduction and was classified
as an extension.

<p/>Such a function must have a return statement, however, since there is no
way to get <tt>void</tt> from <tt>auto&</tt>.

<blockquote><pre>
auto& f() { } // error, no return statement
</pre></blockquote>

<h3>Difference from decltype</h3>

<p/>Unfortunately, there is no way to get the effect of <tt>decltype</tt>
with an <tt>auto</tt> return type; plain <tt>auto</tt> never deduces to a
reference, and <tt>auto&&</tt> always deduces to a reference.  This is a
significant problem, as it means that forwarding functions can't
use <tt>auto</tt>.  We could consider using <tt>decltype</tt> semantics
instead of the existing <tt>auto</tt> semantics, but that would mean giving
different deduction semantics to <tt>auto</tt> depending on whether the
declaration is of a variable or a function, and making <tt>auto</tt>
functions different from lambdas.

<p/>Therefore, I propose to also allow <tt>decltype(auto)</tt> to
get the <tt>decltype</tt> semantics without having to repeat the
expression.  For simplicity of specification and orthogonality I propose to
allow it everywhere that plain <tt>auto</tt> is allowed, except for
introducing a <i>trailing-return-type</i>.  It occurs to me that the
difference in meaning of <tt>decltype</tt> depending on the form of the
expression (e.g. parenthesized or not) might be more surprising in this
context, but I think it would be even more surprising if this worked
differently from C++11 <tt>decltype</tt>.

<h3>noexcept</h3>

<p/>A few people have requested that an <tt>auto</tt> function should have
a deduced noexcept-specifier as well as return type.  I don't think that
tying the two deductions together is appropriate, but if people want
general deduction of noexcept-specifiers, EWG might wish to
revisit <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3207.htm">N3207</a>.

<h3><tt>auto</tt> in <i>trailing-return-type</i></h3>

This proposal initially did not allow <tt>auto</tt> in
a <i>trailing-return-type</i>, but since then it was pointed out that
putting it there is the only way to specify that a lambda returns by
a deduced reference type:

<blockquote><pre>[]()->auto& { return f(); }</pre></blockquote>

<h3>Deducing <tt>std::initializer_list</tt></h3>

Although a variable declared <tt>auto</tt> and initialized with a
brace-enclosed initializer list gets a type
of <tt>std::initializer_list</tt>, we don't want that for a function return
type; since the underlying array is allocated on the stack, it would
immediately leak on return, and any use of the return value would have
undefined behavior.
<strong>
<h3>virtual</h3>

It would be possible to allow return type deduction for virtual functions,
but that would complicate both override checking and vtable layout, so it
seems preferable to prohibit this.
</strong>

<h2>Proposed wording</h2>

Change 7.1.6.2&para;1:

<blockquote>
<dl>
  <dt><i>decltype-specifier:</i></dt>
  <dd><tt>decltype ( </tt><i>expression</i><tt> )</tt></dd>
  <dd><ins><tt>decltype ( auto )</tt></ins></dd>
</dl>
</blockquote>

Change 7.1.6.2&para;4:

<blockquote>
<ins>For an expression <i>e</i>,</ins>

The type denoted by decltype(e) is defined as follows:
<ul>
<li>if e is an unparenthesized id-expression or an unparenthesized class member access (5.2.5), decltype(e)
is the type of the entity named by e. If there is no such entity, or if e names a set of overloaded func-
  tions, the program is ill-formed;</li>
<li>otherwise, if e is an xvalue, decltype(e) is T&&, where T is the type of e;</li>
<li>otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;</li>
<li>otherwise, decltype(e) is the type of e.</li>
</ul>
The operand of the decltype specifier is an unevaluated operand (Clause 5).
[ Example:
<blockquote><pre>
const int&& foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1 = i;   // type is const int&&
decltype(i) x2;           // type is int
decltype(a->x) x3;        // type is double
decltype((a->x)) x4 = x3; // type is const double&
</pre></blockquote>
&mdash;end example ]
<strong>
<p/><ins>For <tt>decltype(auto)</tt>, see 7.1.6.4.</ins></strong>

</blockquote>
Change 7.1.6.4:

<blockquote>
The auto <ins>and <tt>decltype(auto)</tt></ins> type-specifier<ins>s designate a placeholder type that will be
replaced later, <strong>either by</strong> deduction from an initializer
or <strong>by explicit specification with</strong></ins> <del>signifies 
that the type of a variable being declared shall be
deduced from its initializer or that a function declarator shall
include</del> a trailing-return-type.

<p/>The <del>auto type-specifier may</del> 
<ins>placeholder type can</ins> appear with a
function declarator <ins>in the <i>decl-specifier-seq</i>, 
<i>type-specifier-seq</i>, <i>conversion-function-id</i>,
or <i>trailing-return-type</i>,</ins>
<del>with a trailing-return-type
(8.3.5)</del> in any context where such a declarator is valid.  <ins>If the
function declarator includes a <i>trailing-return-type</i> (8.3.5), that specifies
the declared return type of the function.
If the declared return type of the function
contains a placeholder type, the return type of the function is deduced
from <tt>return</tt> statements in the body of the function, if any.</ins>

<p/><del>Otherwise, the type of the variable</del> <ins>The type of a
variable declared using <tt>auto</tt>
or <tt>decltype(auto)</tt></ins> is deduced from its
initializer. <del>The name of the variable being declared shall not appear in
the initializer expression.</del> This use <del>of auto</del> is allowed when declaring
variables in a block (6.3), in namespace scope (3.3.6), and in a
for-init-statement (6.5.3). auto <ins>or decltype(auto)</ins>
shall appear as one of the decl-specifiers
in the decl-specifier-seq and the decl-specifier-seq shall be followed by
one or more init-declarators, each of which shall have a non-empty
initializer.

<p/>[ Example:
<blockquote><pre>
auto x = 5;                 // OK: x has type int
const auto *v = &x, u = 6;  // OK: v has type const int*, u has type const int
static auto y = 0.0;        // OK: y has type double
auto int r;                 // error: auto is not a storage-class-specifier
<ins>auto f() -> int;             // OK: f returns int</ins>
<ins>auto g() { return 0.0; }     // OK: g returns double</ins>
<ins>auto h();                    // OK, h's return type will be deduced when it is defined</ins>
</pre></blockquote>
&mdash; end example ]

<p/><del>The auto type-specifier</del>
<ins>A placeholder type</ins> can also be used in declaring a variable in the
condition of a selection statement (6.4) or an iteration statement (6.5),
in the type-specifier-seq in the new-type-id or type-id of a new-expression
(5.3.4), in a for-range-declaration, and in declaring a static data member
with a brace-or-equal-initializer that appears within the
member-specification of a class definition (9.4.2).

<p/>A program that uses auto <ins>or decltype(auto)</ins> 
in a context not explicitly allowed in this section is ill-formed.

<p/><del>Once the type of a declarator-id has been
determined according to 8.3, the type of the declared variable using the
declarator-id</del> <ins>When a variable declared
using a placeholder type is
initialized, or a <tt>return</tt> statement occurs in a function declared
with a return type that contains a placeholder type, the deduced return type or
variable type</ins> is determined from the type of its initializer<ins>.
In the case of a <tt>return</tt> with no operand, the initializer is considered to be <tt>void()</tt>.
Let T be the declared type of the variable or return type of the function.</ins>

<p/><ins>If the placeholder <strong>is</strong> the <tt>auto</tt> type-specifier,
the deduced type is determined</ins> using
the rules for template argument
deduction. <del>Let T be the declared type that has been determined for a variable identifier d.</del> 
<ins>If the deduction is for a <tt>return</tt> statement and the
initializer is a braced-init-list (8.5.4), the program is ill-formed.  Otherwise,</ins>
Obtain P from T by
replacing the occurrences of auto with either a new invented type template parameter U or, if the initializer
is a braced-init-list <del>(8.5.4)</del>, with std::initializer_list&lt;U>.
<strong><del>The type deduced for the variable d is then the deduced A
determined</del> <ins>Deduce a value for <tt>U</tt></ins></strong> using
the rules of template argument deduction from a function call (14.8.2.1),
where P is a function template parameter type and the initializer <del>for d</del> is the corresponding argument.  If
the deduction fails, the declaration is ill-formed. <strong><ins>Otherwise,
the type deduced for the variable or return type is obtained by
substituting the deduced <tt>U</tt> into <tt>P</tt>.</ins></strong>
[ Example:
<blockquote><pre>
auto x1 = { 1, 2 };    // decltype(x1) is std::initializer_list&lt;int>
auto x2 = { 1, 2.0 };  // error: cannot deduce element type
</pre></blockquote>
&mdash; end example ]

<p/><ins>If the placeholder <strong>is</strong> the <tt>decltype(auto)</tt>
type-specifier, <strong>the declared type of the variable or return type of
the function shall be the placeholder alone.</strong> The <strong>type
deduced for the variable or return type</strong> is determined <strong>as
described in 7.1.6.2,</strong> as though the initializer had been the
operand of the <tt>decltype</tt>.  [ Example:</ins>
<blockquote><pre>
<ins>int i;</ins>
<ins>int&& f();</ins>
<strong><ins>auto           x3a = i;        // decltype(x3a) is int</ins></strong>
<ins>decltype(auto) x3d = i;        // decltype(x3d) is int</ins>
<strong><ins>auto           x4a = (i);      // decltype(x4a) is int</ins></strong>
<ins>decltype(auto) x4d = (i);      // decltype(x4d) is int&</ins>
<strong><ins>auto           x5a = f();      // decltype(x5a) is int</ins></strong>
<ins>decltype(auto) x5d = f();      // decltype(x5d) is int&&</ins>
<strong><ins>auto           x6a = { 1, 2 }; // decltype(x6a) is std::initializer_list&lt;int></ins></strong>
<ins>decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression</ins>
<strong><ins>auto          *x7a = &i;       // decltype(x7a) is int*</ins></strong>
<strong><ins>decltype(auto)*x7d = &i;       // error, declared type is not plain decltype(auto)</ins></strong>
</pre></blockquote>
<ins>&mdash; end example ]</ins>

<p/>If the list of declarators contains more than one declarator, the type of each declared variable is determined
as described above. <ins>If a function with a declared return type that
contains a placeholder type has multiple <tt>return</tt> statements, the return type
is deduced for each <tt>return</tt> statement.</ins>  <ins>In
either case,</ins> if the type deduced <strong><del>for the template parameter U</del></strong> is not
the same in each deduction, the
program is ill-formed.
[ Example:
<blockquote><pre>
const auto &i = expr;
</pre></blockquote>
The type of i is the deduced type of the parameter u in the call f(expr) of the following invented
function template:
<blockquote><pre>
template &lt;class U> void f(const U& u);
</pre></blockquote>
&mdash; end example ]

<p/><ins>If a function with a declared return type that uses a placeholder type has
no <tt>return</tt> statements, the return type is deduced as though from
a <tt>return</tt> statement with no operand at the closing brace of the
function body. [ Example:</ins>
<blockquote><pre>
<ins>auto  f() { } // OK, return type is void
auto* g() { } // error, cannot deduce auto* from void()</ins>
</pre></blockquote>
<strong><ins>&mdash; end example ]</ins></strong>

<p/><ins>If <strong>the type of an entity with an undeduced placeholder
type is needed to determine the type of an expression, the program</strong>
is ill-formed.  But once a <tt>return</tt>
statement has been seen in a function, the return type deduced from that
statement can be used in the rest of the function, including in other
<tt>return</tt> statements.
[ Example:</ins>
<blockquote><pre>
<ins>auto n = n; // error, n's type is unknown</ins>
<ins>auto f();</ins>
<ins>void g() { &amp;f; } // error, f's return type is unknown</ins>
<ins>auto sum(int i) {</ins>
  <ins>if (i == 1)</ins>
    <ins>return i;  // sum's return type is int</ins>
  <ins>else</ins>
    <ins>return sum(i-1)+i; // OK, sum's return type has been deduced</ins>
<ins>}</ins>
</pre></blockquote>
<ins>&mdash;end example]</ins>

<p/><ins>Return type deduction for a function template with a placeholder
in its declared type occurs <strong>when the definition is instantiated</strong> even
if the function body
contains a <tt>return</tt> statement with a non-type-dependent operand.
[ Note: So any use of a specialization of the function template will cause
an implicit instantiation.
<strong>Any errors that arise from this instantiation are
not in the immediate context of the function type, and can result in the program
being ill-formed.</strong>
&mdash;end note ] [ Example:</ins>
<blockquote><pre>
<ins>template &lt;class T> auto f(T t) { return t; } // return type deduced at instantiation time</ins>
<ins>typedef decltype(f(1)) fint_t; // instantiates f&lt;int> to deduce return type</ins>
<ins><strong>template&lt;class T> auto f(T* t) { return *t; }
void g() { int (*p)(int*) = &amp;f; } // instantiates both 'f's to determine return types, chooses second</strong></ins>
</pre></blockquote>
<ins>&mdash;end example]</ins>

<p/><ins>Redeclarations or specializations of a function or function template
with a declared return type that uses a placeholder type 
<strong>shall</strong> also use that placeholder, not
a deduced type. [ Example:</ins>
<blockquote><pre>
<ins>auto f();
auto f() { return 42; } // return type is int
auto f(); // OK
int f();  // error, cannot be overloaded with auto f()
decltype(auto) f(); // error, auto and decltype(auto) don't match

template &lt;typename T> auto g(T t) { return t; } // #1
template auto g(int);      // OK, return type is int
template char g(char);     // error, no matching template
template<> auto g(double); // OK, forward declaration with unknown return type

template &lt;class T> T g(T t) { return t; } // OK, not functionally equivalent to #1
template char g(char);     // OK, now there is a matching template
template auto g(float);    // still matches #1

void h() { return g(42); } // error, ambiguous

<strong>template &lt;typename T> struct A {
  friend T frf(T);
};
auto frf(int i) { return i; } // not a friend of A&lt;int></strong>
</pre></blockquote>

<p/><strong><ins>A function declared with a return type that uses a
placeholder type shall not be <tt>virtual</tt> (10.3).</ins></strong>

<p/><strong><ins>An explicit instantiation declaration (14.7.2) does not
cause the instantiation of an entity declared using a placeholder type, but
it also does not prevent that entity from being instantiated as needed to
determine its type. [ Example:</ins>
<blockquote><pre><ins>
template &lt;typename T> auto f(T t) { return t; }
extern template auto f(int); // does not instantiate f&lt;int>
int (*p)(int) = f;           // instantiates f&lt;int> to determine its return type, 
                             // but an explicit instantiation definition is still required somewhere in the program
</ins></pre></blockquote>
<ins>&mdash;end example ]</ins></strong>


</blockquote>

Change 5.1.2&para;4:

<blockquote>
If a lambda-expression does not include a lambda-declarator, it is as if the lambda-declarator were (). <del>If
a lambda-expression does not include a trailing-return-type, it is as if the trailing-return-type denotes the
following type:</del>
<ul>
<li><del>if the compound-statement is of the form</del>
<blockquote>
<del>{ <i>attribute-specifier-seq</i>opt <tt>return</tt> <i>expression</i> ; }</del>
</blockquote>
<del>the type of the returned expression after lvalue-to-rvalue conversion (4.1), array-to-pointer conver-
  sion (4.2), and function-to-pointer conversion (4.3);</del></li>
<li><del>otherwise, void.</del></li>
</ul>
<ins>The lambda return type is <tt>auto</tt>, which is replaced by
the <i>trailing-return-type</i> if provided and/or deduced
from <tt>return</tt> statements as described in 7.1.6.4.</ins>  [ Example:
<blockquote><pre>
auto x1 = [](int i){ return i; }; // OK: return type is int
auto x2 = []{ return { 1, 2 }; }; // error: <ins>deducing return type from braced-init-list</ins> <del>the return type is void (a</del>
                                  <del>// braced-init-list is not an expression)</del>
<ins>int j;
auto x3 = []()->auto&& { return j; }; // OK: return type is int&</ins>
</pre></blockquote>
&mdash; end example ]
</blockquote>

<strong>Change 14.7.2&para;10:</strong>

<blockquote>
Except for inline functions<strong><ins>, declarations with types deduced
from their initializer or return value (7.1.6.4), </ins></strong> and class
template specializations, explicit instantiation declarations have the
effect of suppressing the implicit instantiation of the entity to which
they refer.
</blockquote>

<h3>References</h3>

Crowl, Lawrence and Alisdair Meredith.  <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2954.html">N2954: Unified Function Syntax</a> (and <a href="http://wiki.edg.com/twiki/bin/viewfile/Wg21santaCruz/CoreWorkingGroup?filename=d2989.html;rev=2">draft revision</a>)

</body>
</html>
