Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deduction failure of function call with explicit template argument list and [temp.arg.explicit]/3

[temp.arg.explicit]/3 of the C++17 standard (final draft) says about deduction of function template arguments with explicitly specified template argument lists:

In contexts where deduction is done and fails, or [...], if a template argument list is specified and it, along with any default template arguments, identifies a single function template specialization, then the template-id is an lvalue for the function template specialization.

How does this apply to parameter packs?

Consider

template<typename...>
struct S {
    S(int) {}
};

template<typename... A>
void f(S<A...>) {}

int main() {
    f<int>(0);
}

This compiles on MSVC, but not on GCC and Clang, see godbolt. It would also be my intuition that it should fail, because deduction will fail, but the quote above seems to imply that even if deduction fails, since f<int> (in my understanding) identifies uniquely a template specialization, f<int> should be considered to refer to that specialization and then call it, without overload resolution, which will work, implicitly converting 0 to S<int>.

What is wrong in my understanding of the quote or is MSVC indeed correct?


Note that if we try to call f<>(0); (which I guess should work by the considerations above) all three compilers refuse to compile.

like image 397
walnut Avatar asked Jan 03 '20 10:01

walnut


2 Answers

Relevant for the question is also [temp.arg.explicit]/6 that tells us that implicit conversions on a function parameter (as you want above) are

if the parameter type contains no template-parameters that participate in template argument deduction. [ Note: Template parameters do not participate in template argument deduction if they are explicitly specified. [...] ]

So, now is the question if A... participates in template argument deduction. (At this point I wanto to note that OPs code compiles also under gcc/clang if we replace the parameter pack by one template parameter, as it should since it is explicitly specified).

One could argue that A... is explicitly specified and therefore does not participate in deduction. But I would argue that one is wrong. [temp.arg.explicit]/9 tells us that deduction can extend explicitly specified template argument lists. Hence, f<int>(S<int, char>{0}); is valid and A... is deduced to int, char. So in this case A... definitely participates in deduction. But since this call only differs from your call by the parameter, the deduction also has to take place in your call, too.

In other words f<int>(0); could also mean to call f<int, char> and as such, it does not specify a single function template specification.

like image 169
n314159 Avatar answered Oct 13 '22 20:10

n314159


It's irrelevant. There's no such thing as a function call "without overload resolution". CWG2092 makes this clear.

[temp.over]/1 controls (broken apart for readability; emphasis mine):

When a call to the name of a function or function template is written (explicitly, or implicitly using the operator notation), template argument deduction ([temp.deduct]) and checking of any explicit template arguments ([temp.arg]) are performed for each function template to find the template argument values (if any) that can be used with that function template to instantiate a function template specialization that can be invoked with the call arguments.

For each function template, if the argument deduction and checking succeeds, the template-arguments (deduced and/or explicit) are used to synthesize the declaration of a single function template specialization which is added to the candidate functions set to be used in overload resolution.

If, for a given function template, argument deduction fails or the synthesized function template specialization would be ill-formed, no such function is added to the set of candidate functions for that template. The complete set of candidate functions includes all the synthesized declarations and all of the non-template overloaded functions of the same name. The synthesized declarations are treated like any other functions in the remainder of overload resolution, except as explicitly noted in [over.match.best].

like image 35
T.C. Avatar answered Oct 13 '22 19:10

T.C.