Trying to understand why the type deduction is failing here with conditional operator.
Something in the standard trying to prevent type deduction in this case? Any pointers to understand this would be great.
auto mfact(int i)
{
return (0==i) ? 1 : i * mfact(i-1);
}
auto mfact2(int i)
{
if (0 == i)
return 1;
else
return i * mfact2(i-1);
}
error: use of ‘auto mfact(int)’ before deduction of ‘auto’ return (0==i) ? 1 : i * mfact(i-1);
The problem in mfact
is the ternary operator. The semantics of that operator specify that the type of the expression is the common type of the two conditional sub-expressions (I'm paraphrasing a bit).
What is the common type? Why it's int
and... A type left to be deduced.
Ah, no problem! What's the type to be deduced? It's the type of the ternary operator...
We have a chicken and egg problem. The entire function definition is ill-formed because the type of the expression cannot be determined.
What about mfact2
? It has two separate return statements. The first one being of a plain integer. Since a function can only have a single return type, return type deduction requires the two return return statements not to conflict.
To quote the C++14 standard revision:
The placeholder type can appear with a function declarator in the decl-specifier-seq, type-specifier-seq, conversion-function-id, or trailing-return-type, in any context where such a declarator is valid. If the function declarator includes a trailing-return-type ([dcl.fct]), 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 return statements in the body of the function, if any.
So one return statement to deduce the type is enough, and:
If a function with a declared return type that contains a placeholder type has multiple return statements, the return type is deduced for each return statement. If the type deduced is not the same in each deduction, the program is ill-formed.
In this simple case, the first statement requires it to be int
, and the second contains a recursive call. Since the same function overload can have only a single return type, the recursive call must be of type int
as well. The two return statements agree.