Is there a restriction imposed by the cyclomatic complexity of a body function?
What the standard indicates (N3797, Β§7.1.6.4):
Let T be the declared type of the variable or the return type of the function. If the placeholder is an auto type specifier, the inferred type is determined using the rules for outputting the template argument. If the output is for the return , and the initializer is braced-init-list (8.5.4), the program is poorly formed. Otherwise, get P from T by replacing the occurrences of auto either the newly invented template parameter of type U or, if the initializer is braced-init-list, with std::initializer_list<U> . Derive the value for U using the rules for deriving a template argument from a function call (14.8.2.1), where P is the type of the function template parameter, and the Initializer is the corresponding argument. If the deduction fails, the declaration is poorly formed. Otherwise, the type deduced for the variable or return type is obtained by substituting the deduced U in P
So tl; dr: the type of the return value is inferred from the expression in the return expression by subtracting the template argument. There is an imaginary template that is called with expressions in the return as function arguments, and the computed argument of the U template will replace the auto in the return type. Now, what happens if we have more than one return statement? Simple: we print return for each return and check if they are compatible:
If a function with a declared return type containing a placeholder type has several return , a return type is output for each return . If the inferred type is not the same in each subtraction, the program is poorly organized.
So for this code:
template<typename T1, typename T2> auto f(T1 const& a, T2 const &b) { if (a > b) return ab; else return a+b; }
The following conclusion is made:
template<typename U> void g(U); g( ab ); g( a+b );
If and only if the same template argument is output in both calls, the code is correctly generated. Otherwise, the output is not executed. If the return type that you set using the automatic specifier is not simple auto , but, for example, auto const& , the parameter of the imaginary template g has the corresponding form:
template<typename U> void g(U const&);
And the challenges will be the same. Again, if the output U is different, the code is poorly formed.
If you do not have a return statement , the return type returned will be void , according to
If a function with a declared return type using a placeholder does not have return , the return type is deduced from a return without an operand in the closing bracket of the function body.
recursion
This gets more complicated if you want recursive functions :
auto f( int a, int b ) { return a? b + a : f(a-1, b);
The problem is explained by the following quote:
If an object type with an unconfirmed placeholder type is required to determine the type of expression, the program is poorly formed. However, once a return been seen in a function, the return type inferred from this statement can be used in the rest of the function, including in other return operations.
So instead we write:
auto f( int a, int b ) { if( a ) return b + a; return f(a-1, b); }
Output:
You can use arbitrarily complex functions if the return all return the same type during the output, and the recursive functions have recursive calls after some non-recursive return statements. If necessary, cite the same types.