28

C++20 allows using auto for function parameter type.

Does it also allow using auto as a template argument placeholder (not similar, but in the spirit of C++17 template<auto> in a way) for function parameter type?

So the following code, pre C++20:

template<typename First, typename Second>
void printPair(const std::pair<First, Second>& p) {
    std::cout << p.first << ", " << p.second;
}

Could be written as:

void printPair(const std::pair<auto, auto>& p) {
    std::cout << p.first << ", " << p.second;
}

It does compile and works nicely with experimental GCC implementation for concepts.

Is it a legitimate syntax with C++20?


Related: Wildcard for C++ concepts saying "accepting anything for this template argument"

Amir Kirsh
  • 12,564
  • 41
  • 74
  • From what I've heard, unconstrained `auto` *directly* translates into templatised `typename XYZ`, which would strongly imply that it is the legitimate syntax. ***Neat***. – Fureeish Feb 23 '20 at 00:38
  • 3
    Note that Clang [disagrees](https://godbolt.org/z/jJZAZw) and that Clang and GCC have the same disagreement about whether `auto` is allowed in `[](const std::pair& p){}` (whether with `-std=c++2a` or `-std=c++17`). – walnut Feb 23 '20 at 02:34
  • 1
    Related: [Is auto in template parameter list in lambdas part of the standard?](https://stackoverflow.com/questions/32322255/is-auto-in-template-parameter-list-in-lambdas-part-of-the-standard) – walnut Feb 23 '20 at 02:41
  • Thank you @DavisHerring - I've fixed the wording – Amir Kirsh Feb 23 '20 at 07:38

1 Answers1

22

This syntax is valid in the C++ Concepts Technical Specification, but not in C++20. In C++20 concepts, auto is only permitted at the top level in a function parameter type. The relevant rule is [dcl.spec.auto] paragraph 2:

A placeholder-type-specifier of the form type-constraint[opt] 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. [Note: Having a generic parameter type placeholder signifies that the function is an abbreviated function template (9.3.3.5 [dcl.fct]) or the lambda is a generic lambda (7.5.5 [expr.prim.lambda]). —end note]

(If you check the wording in the most recent working draft at the time of writing, you will find a somewhat different rule. The above rule was modified by core issue 2447, which was voted into the C++20 final draft at the Prague committee meeting a week ago.)

The decl-specifiers in a function parameter are the initial sequence of keywords and type names at the start of the parameter declaration. The above rule allows auto there at the top level:

void f(auto x);

... but only as a decl-specifier. auto is not permitted when nested within a decl-specifier:

void f(std::vector<auto> x);

... and is also not permitted elsewhere in the parameter type:

void f(void (*p)(auto));
Richard Smith
  • 13,696
  • 56
  • 78
  • Wow, I didn't know that! The CWG link currently gives 404, so can you briefly explain the rationale for this restriction? – L. F. Feb 23 '20 at 02:36
  • 1
    Sorry, the CWG issue and its wording change isn't publicly visible yet. The rule in question was introduced by http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1141r2.html and the intent / rationale was to be consistent with what we already allowed for generic lambdas. – Richard Smith Feb 23 '20 at 02:43
  • 4
    @L.F.: The CWG issue isn’t really relevant anyway: it corrected a wording error that implied that certain uses of `auto` for a trailing return type counted as this kind of `auto` usage. – Davis Herring Feb 23 '20 at 02:48
  • Are functions with `auto` parameters (`void f(auto x) {}`) limited to being defined in header files just like templated functions? Is it possible to explicitly instantiate them as well in order to define them in a separate `cpp` source file? – 303 Jun 15 '22 at 00:45