template <typename T>
struct X
{
template <typename Iter>
X(Iter a, Iter b) {}
template <typename Iter>
auto f(Iter a, Iter b)
{
return X(a, b);
}
};
In the "C++ Templates, The Complete Guide" 2nd edition, there was the previous example about the subtitles of implicit deduction guides with injected class names. The author mentioned that class argument deduction is disabled for injected class names because the type of the return of f would be X<Iter>
due to the implicit deduction guide. But I believe the implicit deduction guide for a template constructor would rather look like the one below.
template <typename T, typename Iter>
X(Iter a, Iter b) -> X<T>;
My question is how would the class template argument types even be deduced in that case T
and Iter
are two distinct types and the parameters types only rely on Iter
. Also even if T could be deduced somehow, T
and Iter
are independent so deducing Iter
from the arguments should not imply that X
has type X<Iter>
right? Is this some error with the text in the book or should the deduction guide look different from what I thought?
You are correct. The implicitly generated deduction guide would indeed look like the one you wrote. And template argument deduction could never deduce T
from it. That indeed won't cause a problem. The problem is with user supplied deduction guides. Like this:
template <typename Iter>
X(Iter a, Iter b) -> X<typename Iter::value_type>;
Which are often added to allow class template argument deduction from iterators. That one could wreak havoc if the injected class name did not suppress argument deduction. The authors may have overlooked the need to add that deduction guide to demonstrate the problem.
Here's an illustration of the problem:
auto v = std::vector<int>{1, 2};
auto x1 = X<float>(begin(v), end(v));
auto x2 = x1.f(begin(v), begin(v));
What's the type of x2
? If we read the class template definition, we expect it to be X<float>
as it would be in C++14, but if class template argument deduction isn't turned off and we add our deduction guide, we'll get X<int>
!
Imagine existing code bases where types suddenly shifted after moving to C++17. That would be very bad.