11
votes

Consider the following code:

#include<iostream>

template<class..., class... T>
int f(T...) { return 1; }

template<class... T>
int f(T...) { return 2; }

int main()
{
    std::cout << f(1);
}

It compiles and prints 1 on gcc 8.2, but fails to compile on clang 7 because of the call f(1) being ambiguous.

If the call is replaced by f() both compiler fail to compile claiming the call to be ambiguous.

If the parameter packs class... T are replaced with a simple parameter class T (and T... with T), both compiler also claim ambiguity.

Which of the compiler is standard-conform in the first example? I suppose this comes down to the specific partial ordering rules for function templates, or is it already ill-formed to use the double parameter pack in this way?

Edit:

My understanding is that the double pack is itself not ill-formed, because [temp.param] 17.1/15 in my reading seems to explicitly allow this if the second pack is deducible from the function arguments, which seems to be the case because of the T... function parameter pack.

It is also possible to specify the first parameter pack's arguments explicitly, though not the second ones and so it is not always the case that (after template argument deduction) at least one parameter pack is empty. I am not sure whether that makes the program ill-formed, because I don't know how to read e.g. [temp.res] 17.7/8.3 in this context.

Both gcc and clang seem to be fine with the double parameter pack itself, e.g. when the second function template overload is removed, both compiler print 1. But this might be a case of ill-formed, no diagnostic required.

Furthermore I assume that with class template argument deduction, a variadic class template could have a variadic constructor template defined, which would imply a constructor candidate similar to my double parameter pack example and as far as I understand the same overload resolution and template argument deduction takes place in that context. This question was motivated by another question with such a setup: Variadic class template deduction fails with gcc 8.2, compiles with clang and msvc See also for a discussion on that: Deduction guides and variadic class templates with variadic template constructors - mismatched argument pack lengths

Now I have also found the answer to the question Deduction guide and variadic templates which I assume implies that gcc is wrong and the call should be considered ambiguous, but I would like to have it verified that this applies here the same way. I would also welcome in a bit more detail the reasoning, because the function template partial ordering rules seem very unclear to me.

1
first f looks ill-formed to me. How could a compiler deterministically deduce the two packs?Richard Hodges
@RichardHodges - {} and {int} (or whatever else is passed as function arguments). A pack can be deduced as empty... I think.StoryTeller - Unslander Monica
@RichardHodges I added some explanation why I it doesn't seem obvious to me that the double pack itself is already ill-formed.user10605163

1 Answers

5
votes

There are two issues here.


First, [temp.deduct.partial]/12 (I also quote the example since it is similar to yours) says:

In most cases, deduction fails if not all template parameters have values, but for partial ordering purposes a template parameter may remain without a value provided it is not used in the types being used for partial ordering. [ Note: A template parameter used in a non-deduced context is considered used. — end note ] [ Example:

template <class T> T f(int);            // #1
template <class T, class U> T f(U);     // #2
void g() {
  f<int>(1);                            // calls #1
}

— end example ]

The types being used for partial ordering are T... according to [temp.deduct.partial]/3:

The types used to determine the ordering depend on the context in which the partial ordering is done:

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

  • ...

So the first unnamed template parameter pack class... does not affect the result of partial ordering. Since there are no other differences for the two function templates, neither is more specialized than the other, resulting an ambiguous call.

This may be related to bug 49505 of GCC.


Second, even though the second function template does not exist, the call should still be ill-formed. According to [temp.arg.explicit]/3:

... A trailing template parameter pack not otherwise deduced will be deduced to an empty sequence of template arguments ...

Only trailing template parameter pack can be deduced to an empty pack, while the first unnamed template parameter pack class... is not a trailing template parameter pack.

Both GCC (bug 69623) and Clang (bug 26435) have bugs for this issue.