Class template argument deduction with partial specialization

741 views Asked by At

I'm having some trouble understanding all the limitations of the new C++17 feature that allows template deduction on constructors.

In particular, this example compiles correctly:

struct B {};

template <typename T, typename = T>
struct A {
    A(T) {}
};

int main() {
    B b;
    A a(b); // ok
}

While this one does not:

struct B {};

template <typename T, typename = T>
struct A;

template <typename T>
struct A<T> {
    A(T) {}
};

int main() {
    B b;
    A a(b); // error
}

The error in this second case is:

main.cpp: In function ‘int main()’:
main.cpp:17:14: error: class template argument deduction failed:
         A a(b);
              ^
main.cpp:17:14: error: no matching function for call to ‘A(B&)’
main.cpp:4:12: note: candidate: template<class T, class> A(A<T, <template-parameter-1-2> >)-> A<T, <template-parameter-1-2> >
     struct A;
            ^
main.cpp:4:12: note:   template argument deduction/substitution failed:
main.cpp:17:14: note:   ‘B’ is not derived from ‘A<T, <template-parameter-1-2> >’
         A a(b);
              ^

Why is this happening?

1

There are 1 answers

0
Barry On BEST ANSWER

Class template argument deduction only considers constructors from the primary class template in order to do deduction. In the first example, we have one constructor that we synthesize a function template for:

template <class T> A<T> __f(T );

The result of __f(b) is A<B>, and we're done.

But in the second example, the primary class template is just:

template <typename T, typename = T>
struct A;

It has no constructors, so we have no function templates to synthesize from them. All we have is a hypothetical default constructor and the copy deduction guide, which together give us this overload set:

template <class T> A<T> __f();
template <class T> A<T> __f(A<T> );

Neither of which are viable for __f(b) (the compile error you get is about trying to match the copy deduction guide), so deduction fails.


If you want this to succeed, you'll have to write a deduction guide:

template <class T>
A(T ) -> A<T>;

Which would allow A a(b) to work.