15

A C++ function can have more than one parameter packs. Although it does not look very practical thing, it is still interesting to know language rules about them.

For example, in case of two overloads:

constexpr int f(auto...) { return 1; }
constexpr int f(auto..., auto...) { return 2; }

Calling f with no arguments f() selects version 1 in MSVC, version 2 in Clang, and ambiguous overloaded call in GCC.

If call f with an argument f(1), then both MSVC and GCC select version 1, while Clang still selects version 2.

Demo: https://gcc.godbolt.org/z/PWr6h1dn1

Which compiler is right here?

There is a similar question Function template overload resolution with two parameter packs, but

  • the functions there have only one parameter pack as function argument (and the second parameter pack is simply unused),
  • the example there results in ambiguity error in all tested compilers (however mentioned compiler bugs are still not resolved). Actually an ambiguity is what one could expect in this example as well, but here most compilers select one of the overloads without an error.
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Fedor
  • 17,146
  • 13
  • 40
  • 131
  • 2
    I have no idea about the correct answer, but I want to challenge the assertion behind the question *“which compiler is right”*. It is possible they all are if the code is UB or ill-formed, no diagnostic required. Not saying it is the case, only that testing the behavior of compilers is not a correct approach to knowing whether a piece of code is legal. – spectras Feb 16 '22 at 21:38
  • 4
    Even in the absence of the first overload, I am surprised that `constexpr int f(auto..., auto...) { return 2; }` even compiles. How would a compiler decide which argument goes to first and which to second pack? – prapin Feb 16 '22 at 21:39
  • 1
    @prapin Template arguments for the first pack can be given explicitly and only the trailing pack can be deduced from function arguments. – user17732522 Feb 16 '22 at 23:13
  • 2
    For the second overload the first parameter pack is neither deduced nor explicitly specified in any of the calls. So if the last part in the answer of the linked question is correct, then the second overload should always fail template argument deduction and the first overload should always be chosen in the given calls. But as mentioned in the bug reports linked there, the compilers currently deduce the first pack as empty in such calls. I am not sure whether that is correct. – user17732522 Feb 16 '22 at 23:47
  • 1
    This is just wild guess: maybe we have here ODR violation case? I mean both function signatures looks functionally identical, but somehow compilers fail to recognize duplicate definitions. So with ODR violated - each compiler is free to select any of two implementations. – PiotrNycz Feb 22 '22 at 19:22

1 Answers1

1

This should result in the program being rejected as ambiguous, in both cases.

Firstly note that:

In the context of a function call, the types used are those function parameter types for which the function call has arguments.

That is, only the actual arguments provided contribute to function template partial ordering. So the presence of a preceding function parameter pack in (2) does not contribute to the process of deduction of one function template against the other; it is deduced as empty and does not contribute further.

Now, the tiebreaker for partial ordering with trailing packs can't help, since both have a trailing pack:

[...] if G has a trailing function parameter pack for which F does not have a corresponding parameter, and if F does not have a trailing function parameter pack, then F is more specialized than G.

But both have a trailing parameter pack, and it is of the same length, so the language on "for which F does not have a corresponding parameter" (which is admittedly not entirely clear; see CWG 1395) doesn't help either.

I think that if template arguments are provided (and they are those that would be deduced), then (2) should be preferred, since in that case its trailing function parameter pack will be shorter. But this is very much not clear; clang agrees with me, but gcc and MSVC take the opposite course.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • This assumes that deducing the first pack as empty is valid. According to the answer [here](https://stackoverflow.com/a/53363067/17732522) and the GCC bug report linked there, it isn't and should be a deduction failure, in which case the second overload isn't even viable. Would you say that this is wrong? – user17732522 Mar 13 '22 at 21:15
  • @user17732522 Yes. The citation there is a note, so not normative. I'll comment further on that answer. Thanks! – ecatmur Mar 14 '22 at 10:02