The operator*
works for std::unique_ptr<std::array<int, 5>>
but not for std::unique_ptr<int[]>
. But why?
Coming from cppreference:
These member functions are only provided for unique_ptr for the single objects i.e. the primary template.
Here:
#include <vector>
#include <memory>
#include <algorithm>
#include <functional>
#include <fmt/core.h>
int main()
{
std::vector<int> data { 1, 2, 3, 4, 5 };
// auto ptr { std::make_unique_for_overwrite<std::array<int, 5> >() };
auto ptr{ std::make_unique_for_overwrite<int[]>(5) };
if (ptr == nullptr) return 1;
auto& out{ *ptr }; // does not compile for <int[]>
std::ranges::transform(data, std::begin(out), std::negate{});
for (const auto v : out)
fmt::print("{} ", v);
fmt::print("\n");
}
Error message:
<source>:16:17: error: no match for 'operator*' (operand type is 'std::unique_ptr<int [], std::default_delete<int []> >')
16 | auto& out { *ptr };
| ^~~~
How can out
be made bound to int[5]
that is pointed to by ptr
? I basically want to make the call to transform
compile for the case of using a std::unique_ptr< int[] > ptr;
.
One working solution that comes to my mind:
// ...
auto out{ ptr.get() };
std::ranges::transform(data, out, std::negate{});
for (const auto v : std::span{ out, 5 })
// ...
But is there another way of doing this without having to touch raw pointers?
Is there another way of doing this without having to touch raw pointers?
Your current solution is far optimal in my opinion.
An alternative might be making a reference-range out of the std::make_unique<int[]>
by calling the std::unique_ptr::operator[]
on each element.
#include <ranges>
#include <memory>
#include <algorithm>
std::vector<int> data{ 1, 2, 3, 4, 5 };
auto ptr{ std::make_unique<int[]>(5) };
auto range = std::views::iota(0u, std::size(data))
| std::views::transform([&ptr](auto idx) -> int& { return ptr[idx]; });
std::ranges::transform(data, std::begin(range), std::negate{});
for (const auto v : range)
std::cout << v;