Can someone please explain why in the following code C choses the specialization but A does not? They look the same to me
#include <iostream>
template <typename T=int>
struct C {
int i=3;
};
template<>
struct C<int> {
int i=4;
};
template <typename T=int>
struct A {
A(int, int) {}
};
template <>
struct A<int> {
A(int) {}
};
int main() {
C c;
std::cout << c.i << '\n'; // prints 4
// A a(5); // does not compile
}
I tested using GCC
CodePudding user response:
Without an explicit template argument list (as in A a
instead of A<> a
) class template argument deduction (CTAD) will be performed.
CTAD basically tries to find a matching constructor for the declaration from which it can deduce the template arguments. But it always considers only constructors in the primary template, not in specializations.
A(int, int) {}
is not a constructor that would be viable for A a(5);
and so it fails.
You need to add deduction guides for your specializations manually to inform CTAD how to decide the template arguments. For example here add the following declaration at namespace scope, for readability probably after your explicit specialization:
A(int) -> A<int>;
or alternatively, making use of the default argument:
A(int) -> A<>;
C c;
is correct, since the implicit default constructor of C
is viable for this declaration and it doesn't need to deduce the template argument since it is defaulted. I could not reproduce Clang or MSVC failing to compile it.
Note however that in general CTAD requires C 17 or later. Before that leaving out the template argument list on a type was simply never allowed.