Reputation: 97
unique_ptr is basically implemented as follows:
template <typename _Tp> // deleter for single object
struct default_delete {
void operator()(_Tp* ptr) const {
delete ptr;
}
};
template <typename _Tp> // deleter for array
struct default_delete<_Tp[]> {
void operator()(_Tp* ptr) const {
delete[] ptr;
}
};
// main template
template <typename _Tp, typename _Dp = default_delete<_Tp>>
class unique_ptr {
public:
typedef _Tp element_type;
typedef _Dp deleter_type;
// ...
};
// array specialized
template <typename _Tp, typename _Dp>
class unique_ptr<_Tp[], _Dp> {
public: // ^ How did this work?
typedef _Tp element_type;
typedef _Dp deleter_type;
// ...
};
When I use int[] as template argument, obviously this will fall into unique_ptr's array version. As far as I know, compiler will match Tp[] with int[], and match Dp with the default template parameter default_delete<_Tp>>. So Tp is deduced to int, and finally the template parameter list deduced will be like this in my thought:
<int[], default_delete<int>>
My question: How did the compiler select default_delete's partial specialization for delete[] ? It seems like there is no reason to choose deleter's int[] version. I think parameter Dp in specialized version and in main template are the same.
Upvotes: 0
Views: 132
Reputation: 172964
Given unique_ptr<int[]>
, the primary template is checked firstly, as the result _Tp
is deduced as int[]
, and _Dp
would be default_delete<int[]>
(from the default value.)
Then the specializations are checked. The specialization is defined as unique_ptr<_Tp[], _Dp>
; from the deduction result got above, it's replaced as unique_ptr<int[], default_delete<int[]>>
, then the template parameter _Tp
and _Dp
of the specialization are deduced as int
and default_delete<int[]>
. (They're independent with the template parameters of the primary template.)
Upvotes: 3
Reputation: 22152
_Tp
in the primary template and _Tp
in the partial specialization are not the same. You could give them different names to distinguish them better.
The default template arguments are taken from the primary template and this gives the default argument
default_delete<_Tp>
for _Dp
. _Tp
here is the _Tp
from the primary template, not from the specialization.
In the specialization, the argument given for the primary template's _Tp
is _Tp[]
, where the latter _Tp
is the specialization's one.
Therefore with e.g. unique_ptr<int[]>
, the specialization is preferred with the specialization's _Tp
equal to int
, but the primary template's _Tp
is int[]
and so the default argument for _Dp
, which is taken from the primary template, is default_delete<int[]>
, not default_delete<int>
.
Upvotes: 4