Baruch
Baruch

Reputation: 21518

Choose class specialization using default template parameter

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

Upvotes: 1

Views: 88

Answers (1)

user17732522
user17732522

Reputation: 76698

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.

Upvotes: 3

Related Questions