5

I was using parameter pack when I noticed that one such case(shown below) compiles fine in gcc and clang but not in msvc:

template<class T> void func(T a, T b= T{})
{
    
}
template<class T, class... S> void func(T a, S... b)
{

}
 
int main()
{
    func(1); // Should this call succeed? 
}

Here is the link for verifying the same: https://godbolt.org/z/8KsrcnMez

As can be seen the above program fails in msvc with the error message:

<source>(13): error C2668: 'func': ambiguous call to overloaded function
<source>(6): note: could be 'void func<int,>(T)'
        with
        [
            T=int
        ]
<source>(2): note: or       'void func<int>(T,T)'
        with
        [
            T=int
        ]
<source>(13): note: while trying to match the argument list '(int)'

But the same compiles fine with gcc and clang.

Which compiler(s) is right here?

Jason
  • 36,170
  • 5
  • 26
  • 60

1 Answers1

1

MSVC is right in rejecting the code. According to temp.func.order#5.example-2 the call func(1) is ambiguous. The example given in the standard is as follows:

Note: Since, in a call context, such type deduction considers only parameters for which there are explicit call arguments, some parameters are ignored (namely, function parameter packs, parameters with default arguments, and ellipsis parameters).

template<class T         > void g(T, T = T());          // #3
template<class T, class... U> void g(T, U ...);         // #4

void h() {
 g(42);                                                // error: ambiguous
}

This means that in the example in question, the call func(1) is ambiguous as well.

Errata

Note that cppreference has errata in below given example:

template<class T>
void g(T, T = T()); // #1
template<class T, class... U>
void g(T, U...);    // #2

void h()
{
   g(42); // calls #1 due to the tie-breaker between parameter pack and omitted parameter
}

As can be seen in the above example, cpprefernce incorrectly says that the first overload #1 should be choosen.

This has been fixed in recent edit that i made.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • 2
    The standard actually has an example saying that this call is ambiguous: https://timsong-cpp.github.io/cppwp/n4861/temp.func.order#5.example-2 – user17732522 Jun 18 '22 at 19:24
  • @user17732522 I have updated the answer to say that cppreference has an errata. And that the call `func(1)` is ambiguous according to the standard. And also the msvc is correct. – Jason Jun 19 '22 at 05:22
  • 2
    @user17732522 Also, i have made an [edit](https://en.cppreference.com/mwiki/index.php?title=cpp/language/function_template&diff=140392&oldid=139771) fixing the example on cppreference. – Jason Jun 19 '22 at 05:43
  • 2
    I was not claiming that the example in the standard is definitively correct. A similar example required correction after [CWG 1395](https://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1395), see https://github.com/cplusplus/draft/issues/2559. I just wanted to show that it might not be as straight-forward as citing cppreference and that "_The same can also be inferred from temp.deduct.partial._" may not be obvious if there is an example saying the opposite. – user17732522 Jun 19 '22 at 06:16
  • @user17732522 I see. In any case i have mentioned both(i.e., the standard's example and the cppreference). Also at least after the edit, cppreference matches the standard. Btw i thought that you were claiming that *"the example in the standard is definitively correct"* because i saw the downvote on my answer and i assumed it was you suggesting that i should correct my answer. – Jason Jun 19 '22 at 06:23
  • Not my downvote. Sometimes it is forgotten to update examples (which are non-normative) with normative changes and this one has been in there since C++11. I think the question is whether "for which F does not have a corresponding parameter" in https://timsong-cpp.github.io/cppwp/n4861/temp.deduct.partial#11 (from CWG1395) applies to the defaulted function parameter without explicit argument in the call as well, or whether it doesn't. I am not sure because https://timsong-cpp.github.io/cppwp/n4861/temp.func.order#5.sentence-1 says (again non-normative) something about parameters being ignored. – user17732522 Jun 19 '22 at 06:36
  • @user17732522 Yes, looking at [temp.deduct.partial#11] and [temp.func.order#5] it is not obvious that whether the call `func(1);` should succeed or not. Most probably the wording needs some clarification. – Jason Jun 19 '22 at 06:50
  • @user17732522 I also asked a separate question [here](https://stackoverflow.com/questions/72671622/msvc-not-able-to-disambiguate-between-function-templates-when-one-of-them-contai) that does not involve a function parameter pack. I am not sure what the standard says about that example. – Jason Jun 19 '22 at 07:00
  • @user17732522 _temp.func.order#5.sentence-1 says (again non-normative) something about parameters being ignored_ Not sure about packs and ellipsis, but there is https://timsong-cpp.github.io/cppwp/n4861/over.match.viable#2.3.sentence-2. The part about ellipsis may be covered by the previous bullet. And packs are ignored because functions produced from their templates do not have packs, but a concrete number of parameters? This part is susp. – Language Lawyer Jun 19 '22 at 09:24