On 2014-07-28 13:09, Andrew Sutton wrote:
3) auto (*f (auto)) (auto); // generic function 'f' constrained to
returning a unary function pointer deduced from the return
expression.
Really? I've read the comment and I'm still not sure how to read this
declaration.
The first and last 'auto' in the line would be resolved by return type
deduction, the second, in the parameter list, would be a synthesized
template argument.
E.g. If the function were defined as
auto (*crazy (auto f)) (auto)
{
return f;
}
then it is only well formed if instantiated with an 'f' that is
convertible to some ptr-to-function type of the form "R (*) (A)". At
which point return type deduction would subst 'R' for the first 'auto'
and 'A' for the last.
If it were passed a pointer to the following function
int F(float);
then it should be instantiated as
int (*crazy (int (*f) (float))) (float)
{
return f;
}
My point with case (3) is that it contains two function parameter lists
that contain 'auto' but they need to be dealt with differently for
generic function template argument synthesis and for return type
deduction.
Ultimately, the last two would require the generalized 'auto'
type deduction behavior. The difficulty is that there doesn't
appear to be any existing means for determining, at parse time
of the first "(auto", whether we're forming a function or
variable declaration. Maybe such state would fall out of a
generalized 'auto' solution.
I was wondering about this on the drive to work this morning. Maybe
trying to pin down semantics at parse time isn't the right approach.
I have a feeling you may be right.
That is, always parse declarations like variables, and then build up
template parameters as needed during grorkdecl or grokfndecl. Or
maybe
that's too late. I don't know.
My thinking was going the other way other initially (assuming a
function until you know it isn't). But I think deduced return types
would cause problems with this so I'm thinking the "assume variable"
route might be better. We'd have to generate some form of parametric
type tree for the variable type before deduction from the initializer
anyway and it may be that such a tree could be transformed into the
function type should the decl turn out to be a function.
I recall my initial experience of implementing generic functions: I
tried to work in the grok*decl space, but found that so many cases had
to be handled explicitly and types rebuilt afterwards potentially after
errors about 'auto' had already been issued (which needed additional
cases to avoid). I remember it being nasty. But it was my first hack
on the GCC code base; so that was probably a factor (still is!).
Switching to the parsing route allowed to transform the code on the fly
as if it had been written with the full template header from the start;
making all the existing code happy. I would like to eliminate the
possibility of making the "during parsing" route work before diving back
in to a post-parse solution.
Whatever the solution for auto, it will be the same for concepts.
We'll just add constraints to the auto-type whenever we find a
constrained-type-specifier.
Agreed.
Adam