Here's the source code of std::default_delete from Visual Studio 2017 Community edition.
template<class _Ty>
struct default_delete<_Ty[]>
{
// default deleter for unique_ptr to array of unknown size
constexpr default_delete() _NOEXCEPT = default;
template<class _Uty, class = typename enable_if<is_convertible<_Uty(*)[], _Ty(*)[]>::value, void>::type>
default_delete(const default_delete<_Uty[]>&) _NOEXCEPT
{
// construct from another default_delete
}
template<class _Uty, class = typename enable_if<is_convertible<_Uty(*)[], _Ty(*)[]>::value, void>::type>
void operator()(_Uty *_Ptr) const _NOEXCEPT
{
// delete a pointer
static_assert(0 < sizeof (_Uty), "can't delete an incomplete type");
delete[] _Ptr;
}
};
I noticed the template parameters _Uty(*)[]
and _Ty(*)[]
in is_convertible<_Uty(*)[], _Ty(*)[]>
inside array specialization.
If it was _Ty(&)[]
then I would know for sure that it's a reference to array of type _Ty, as covered in this post, but have no clue whatsoever on what _Ty(*)[]
means.
It'll be really helpful if someone can shed light on this exotic template param.
EDIT: Many thanks to all of ya! I managed to rig up a function taking pointer to array.
template <typename T>
T* func0(T(*parr)[], std::initializer_list<T> args)
{
int i = 0;
for (T arg : args)
(*parr)[i++] = arg;
return *parr;
}
template <typename T, unsigned S>
T* func1(T(*parr)[S], std::initializer_list<T> args)
{
int i = 0;
for (T arg : args)
(*parr)[i++] = arg;
return *parr;
}
int main(void)
{
std::string strs[5];
//std::string* pstrs = func1(&strs, {"133", "233", "333", "433", "533"}); // Not working! Cannot deduce template param T from args
std::string* pstrs = func1<std::string, 5>(&strs, {"133", "233", "333", "433", "533"}); // Works fine!
//std::string* pstrs = func0<std::string, 5>(&strs, {"133", "233", "333", "433", "533"}); // Not working! No instance of function template match
return 0;
}
I wonder why template param T cannot be deduced from args passed to func1 ?
Also, it seems that the size information S
in T(*parr)[S]
is a must.