auto ( expression ) in direct initialization argument

106 Views Asked by At

In C++23 we have explicit type convertion auto ( expression ), and according to cppreference it is already supported by both GCC and Clang.

I have a question where such cast does not occur for some reason. Consider the program:

// OK, x = 0
int x(int(auto(0)));

// OK, f is function template
int f(auto(x));

// error
int y(int(auto(x)));

Here x declaration is accepted, but very similar y declaration does not. Online demo: https://godbolt.org/z/f9zor3eTv

GCC:

error: 'auto' parameter not permitted in this context

Clang:

error: 'auto' not allowed in function prototype that is not a function declaration

Is declaration of y really illegal and compilers are correct in rejecting it?

1

There are 1 best solutions below

0
On BEST ANSWER

Had you had a type instead of auto, it would read like:

int y(int(long(x)));
// ->
int y(int(long x));
// ->
int y(int(*)(long));

However, you cannot put auto in place of long.

[dcl.fct]p22:

An abbreviated function template is a function declaration that has one or more generic parameter type placeholders ([dcl.spec.auto]). [...]

[dcl.spec.auto.general]p2

A placeholder-type-specifier of the form type-constraintopt auto can be used as a decl-specifier of the decl-specifier-seq of a parameter-declaration of a function declaration or lambda-expression and, if it is not the auto type-specifier introducing a trailing-return-type (see below), is a generic parameter type placeholder of the function declaration or lambda-expression.

... So the auto can only be a decl-specifier directly in the decl-specifier-seq of the type, not nested further. Basically, if you can move the auto all the way to the left, it will work.

So these abbreviated function templates work:

int y(auto x);
int y(auto* x);
int y(auto const*& x);
int y(const auto*& x);
int y(auto* x[][12]);
int y(auto (*x)[3][4]);
int y(auto (*fn)(int x));
// Last one can be written as:
int y(auto(int x));
int y(auto(int(x)));

And these ones won't:

int y(std::vector<auto> x);
int y(void (*fn)(auto));
int y(int x[sizeof(auto)]);

The exact same restrictions apply to placeholder types in initializers, like auto x = ...;:

int f(int);

auto (*ptr1)(int) = f;  // Works
// int (*ptr2)(auto) = f;  // Doesn't