The following program is reduced from the code in this question:
template <typename T, void (*)(T), typename = void>
struct S;
template <typename T, void (*f)(T)>
struct S<T, f, void> {};
S<int const, nullptr> s;
In all versions of GCC, in all language revisions, the specialization of S
is chosen when s
is instantiated.
In all versions of Clang, but only from C++17 onward, the primary template is chosen when instantiating s
.
Some points I think worth noting are that the primary is never chosen if the instantiation is over <int, nullptr>
, i.e. the first parameter is no longer int const
. Also, the primary is never chosen if the signature of the function pointer in the second parameter doesn't contain T
as the argument, i.e. if the second parameter is T (*)()
, or void (*)()
, say.
If this code isn't IFNDR, which compiler is correct? Is there some breaking change in the C++17 language revision?
This is because C++17 allowed a template type argument to be deduced from the type of a non-type argument. [temp.deduct.type]/13:
When the value of the argument corresponding to a non-type template parameter
P
that is declared with a dependent type is deduced from an expression, the template parameters in the type ofP
are deduced from the type of the value.
So when we try to match S<int const, nullptr>
against the partial specialization, we deduce the partial specialization's template parameter T
from two sources:
int const
, we deduce T
= int const
void (*)(int)
because the top-level cv-qualification of function parameters are adjusted away), we deduce T
= int
.Since we deduced conflicting results, the deduction fails and the partial specialization is not a match.
Similar examples were brought up on the core reflector back in 2019. There was some agreement that this was a defect in the standard, and that deduction from the type of a non-type template argument should only happen for things that are not otherwise deducible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With