#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?