Class template argument deduction not working with alias template
This was a feature that we considered when formulating the proposal, but it was eventually cut from the C++17 feature set because we didn't yet have a good enough design for it. In particular, there are some subtleties regarding how you select and transform deduction guides from the aliased template into deduction guides for the alias template. There are also open questions as to how to behave if the alias template is not a simple alias for another template. Some examples:
template<typename T> struct Q { Q(T); }; // #1
template<typename T> struct Q<T*> { Q(T); }; // #2
template<typename U> using QP = Q<U*>;
int *x;
Q p = x; // deduces Q<int*> using #1, ill-formed
QP q = x; // deduces Q<int*> using #1, or
// deduces Q<int**> using #2?
template<typename T> Q(T) -> Q<T>; // #3
QP r = x; // can we use deduction guide #3 here?
template<typename T> Q(T*) -> Q<T**>; // #4
int **y;
QP s = y; // can we use deduction guide #4 here?
template<typename T> struct A { typedef T type; struct Y {}; };
template<typename T> using X = typename A<T>::type;
template<typename T> using Y = typename A<T>::Y;
X x = 4; // can this deduce T == int?
Y y = A<int>::Y(); // can this deduce T == int?
There are decent answers to the above questions, but tackling them adds complexity, and it seemed preferable to disallow deduction for alias templates for C++17 rather than rush something flawed in.
Update [C++20]: This topic was revisited for C++20, and we approved P1814R0, which permits class template argument deduction for alias templates.
The original example is now valid. For the examples above:
CTAD still only considers constructors from the primary template. So in
QP q = x;
, #2 is not considered, and instead #1's constructor is used. That constructor is implicitly converted into a guide forQ
:template<typename T> Q(T) -> Q<T>;
which is then converted into a guide for the alias template
QP
by deducing the right-hand side of the guide forQ
(Q<T>
) from the right-hand side of the alias template (Q<U*>
), which deducesT
=U*
, then substituting that back into the guide, thereby producing the equivalent of:template<typename U> Q(U*) -> Q<U*>; // ... which is effectively ... template<typename U> QP(U*) -> QP<U>; // ... except that explicit deduction guides are not // permitted for alias templates
That guide is then used to deduce the type of
q
, which deducesU
=int
, so the type ofq
isQ<int*>
, so the initialization ofq
is ill-formed.The initialization of
r
does consider deduction guide #3, which is transformed into a guide forQP
as described aboveThe initialization of
s
does consider deduction guide #4; deducingQ<T**>
fromQ<U*>
deduces nothing, so we retain the deduction guidetemplate<typename T> Q(T*) -> Q<T**>;
as-is, but add a constraint that the result of deduction must match the form of
QP
. We then deduceT
=int
, substitute that in to compute a result type ofQ<int**>
, and check that we can deduceQP<U>
fromQ<int**>
, which we can. So the type ofs
is deduced asQ<int**>
.CTAD for alias templates is only supported where the right-hand side of the alias template is a simple-template-id (of the form
maybe::stuff::templatename<args>
). So neitherX
norY
is deducible.
From http://en.cppreference.com/w/cpp/language/template_argument_deduction, "Alias templates are never deduced." So, it is by design.