Reputation: 2399
When you have class template argument deduction available from C++17, why can't you deduce the template arguments of std::unique_ptr? For example, this gives me an error:
std::unique_ptr smp(new D);
That says "Argument list of class template is missing".
Shouldn't the template arguments (at least the pointer type) be deducable?
any declaration that specifies initialization of a variable and variable template
Upvotes: 26
Views: 3989
Reputation: 2934
So this is a side effect from those olden times at the beginning of C++, when the standard makers decided to have two different delete
and delete[]
operators for pointers to objects and pointers to arrays of objects.
In these modern times of C++, where we have templates (they weren't there from the beginning), std::array
(for fixed sized arrays), inititalizer lists (for static fixed sized arrays) and std::vector
(for dynamically sized arrays), almost nobody will need the delete[]
operator anymore. I have never used it, and I wouldn't be surprised, if the vast majority of the readers of this question have not used it, either.
Removing int* array = new int[5];
in favour of auto* array = new std::array<int, 5>;
would simplify things and would enable safe conversion of pointers to std::unique_ptr
and std::shared_ptr
. But it would break old code, and so far, the C++ standard maintainers have been very keen on backwards compatibility.
Nobody stops you, though, from writing a small inlined templated wrapper function:
template<typename T>
std::unique_ptr<T> unique_obj_ptr(T* object) {
static_assert(!std::is_pointer<T>::value, "Cannot use pointers to pointers here");
return std::unique_ptr<T>(object);
}
Of course, you can also create a similiar function shared_obj_ptr()
to create std::shared_ptr
s, and if you really need them, you can also add unique_arr_ptr()
and shared_arr_ptr()
.
Upvotes: 0
Reputation: 170064
I'm not going to repeat the rationale in @NathanOliver's great answer, I'm just going to mention the how of it, the mechanics, which is what I think you are also after. You are right that if the constructor of unique_ptr
looked merely like...
explicit unique_ptr( T* ) noexcept;
... it'd be possible to deduce T
. The compiler generated deduction guide would work just fine. And that would be a problem, like Nathan illustrates. But the constructor is specified like this...
explicit unique_ptr( pointer p ) noexcept;
... where the alias pointer
is specified as follows:
pointer
:std::remove_reference<Deleter>::type::pointer
if that type exists, otherwiseT*
. Must satisfy NullablePointer.
That specification essentially means that pointer
must be an alias to __some_meta_function<T>::type
. Everything on the left of ::type
is a non-deduced context, which is what prevents the deduction of T
from pointer
. That's how these sort of deduction guides could be made to fail even if pointer
needed to be T*
always. Just by making it a non-deduced context will prevent the viability of any deduction guide produced from that constructor.
Upvotes: 22
Reputation: 180510
Lets look at new int
and new int[10]
. Both of those return an int*
. There is no way to tell if you should have unique_ptr<int>
or unique_ptr<int[]>
. That right there is enough not to provide any sort of deduction guide.
Upvotes: 29