This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115d. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2024-10-26
[Accepted as a DR at the February, 2019 meeting.]
The status of an example like the following is not clear:
template <typename... T> struct A; template <> struct A<> {}; template <typename T, typename... Ts> struct A<T, Ts...> : A<Ts...> {}; struct B : A<int> {}; template <typename... T> void f(const A<T...>&); void g() { f(B{}); }
This seems to be ambiguous in the current wording because A<> and A<int> both succeed in deduction. It would be reasonable to prefer the more derived specialization.
Notes from the March, 2018 meeting:
The relevant specification is in 13.10.3.2 [temp.deduct.call] bullet 4.3 and paragraph 5, which specifies that if there is more than one possible deduced A, deduction fails. The consensus was to add wording similar to that of overload resolution preferring “nearer” base classes.
Proposed resolution (November, 2018):
Change 13.10.3.2 [temp.deduct.call] bullet 4.3 as follows:
In general, the deduction process attempts to find template argument values that will make the deduced A identical to A (after the type A is transformed as described above). However, there are three cases that allow a difference:
...
If P is a class and P has the form simple-template-id, then the transformed A can be a derived class D of the deduced A. Likewise, if P is a pointer to a class of the form simple-template-id, the transformed A can be a pointer to a derived class D pointed to by the deduced A. However, if there is a class C that is a (direct or indirect) base class of D and derived (directly or indirectly) from a class B and that would be a valid deduced A, the deduced A cannot be B or pointer to B, respectively. [Example:
template <typename... T> struct X; template <> struct X<> {}; template <typename T, typename... Ts> struct X<T, Ts...> : X<Ts...> {}; struct D : X<int> {}; template <typename... T> int f(const X<T...>&); int x = f(D()); // calls f<int>, not f<> // B is X<>, C is X<int>—end example]