#include<type_traits>
template <typename T, T>
struct A { };
template <typename T, T t>
void f(A<T, t>) {
}
int main() {
f(A<const int, 0>{});
}
https://godbolt.org/z/n6bcj5rjM
The program is accepted by GCC and ICC in C++14 and C++17 mode, as well as Clang in C++14 mode but rejected by Clang in C++17 mode and MSVC in either mode.
Rejections are with diagnostics like this:
<source>:12:5: error: no matching function for call to 'f'
f(A<const int, 0>{});
^
<source>:7:6: note: candidate template ignored: deduced conflicting types for parameter 'T' ('const int' vs. 'int')
void f(A<T, t>) {
^
Also consider the following variation:
const int i = 0;
int main() {
f(A<const int&, i>{});
}
https://godbolt.org/z/oa3xfv4jx
The same compilers still accept/reject and those rejecting now complain about a type mismatch between const int&
and int
.
Which compiler(s) are correct?
I expect the answer to depend on whether it is before or after C++17, since C++17 introduced a (breaking) change in non-type template argument deduction, see [diff.cpp14.temp].
In particular for C++17 and later I am wondering whether deduction of T
from the argument for t
is supposed to deduce the type of the template parameter, which would be int
in the first variant (because top-level const
is ignored) and const int&
in the second variant, or whether the usual expression adjustments are supposed to be applied as in deduction with auto ... = t;
, in which case the second variant should deduce T
to int
.
Is it then really intended that template argument deduction fails if these types mismatch with the explicitly provided type for T
?