I've been trying to use std::binary_search
and std::lower_bound
on std::array<unique_ptr<int>>
just to get to grips with it. I was having trouble with the following :
#include <array>
#include <memory>
#include <algorithm>
int main() {
std::array<std::unique_ptr<int>, 3> a = {std::make_unique<int>(1),
std::make_unique<int>(2), std::make_unique<int>(5)};
auto t = std::binary_search(a.begin(), a.end(), 5, []
(std::unique_ptr<int> x, std::unique_ptr<int> y) {
return x.get() < y.get();
});
return 0;
}
I'm trying to put my own comparison here, similar to how it would be done with something like std::sort
. However when compiling this I have an error cannot convert argument 1 from 'const _Ty' to 'std::unique_ptr<int,std::default_delete<int>>'
What should I change to make this work?
EDIT : complete error message from Visual Studio
Severity Code Description Project File Line Suppression State Details
Error C2664 'bool thng_already::<lambda_1>::operator ()(std::unique_ptr<int,std::default_delete<int>>,std::unique_ptr<int,std::default_delete<int>>) const': cannot convert argument 1 from 'const _Ty' to 'std::unique_ptr<int,std::default_delete<int>>'
with
[
_Ty=int
] Proj C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\algorithm 7028
When replacing 5 with std::make_unique<int>(5)
we have a different error
Severity Code Description Project File Line Suppression State Details
Error C2280 'std::unique_ptr<int,std::default_delete<int>>::unique_ptr(const std::unique_ptr<int,std::default_delete<int>> &)': attempting to reference a deleted function Proj C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\algorithm 7028
There are three issues:
Your lambda takes its parameters by value. This implies that the binary_search
implementation has to copy the arguments when passing them to the lambda. Can you copy unique_ptr
? No. That's why it's not working. Take the arguments by const reference instead.
The lambda cannot accept 5
as one of its arguments since 5 is not a unique_ptr<int>
You Compare x.get() < y.get()
. get()
returns the raw pointer to the integer, so you compare pointers, not the values that these pointers point to. I assume you mean *x < *y
to compare the integers instead
int main() {
std::array<std::unique_ptr<int>, 3> a = {
std::make_unique<int>(1),
std::make_unique<int>(2),
std::make_unique<int>(5)};
auto t = std::binary_search(a.begin(), a.end(),
std::make_unique<int>(5),
[](const std::unique_ptr<int>& x, const std::unique_ptr<int>& y) {
return *x < *y;
});
return 0;
}
Feel free to shorten the lambda declaration to [](const auto& x, const auto& y)
and rely on type deduction.
Calling make_unique<int>(5)
does a temporary allocation that is not strictly necessary. To avoid it, we need to augment the comparator to accept int
and std::unique_ptr<int>
as its arguments in either order. This is probably the easiest approach to do so:
struct Compare {
bool operator()(const std::unique_ptr<int>& left, int right) const
{ return *left < right; }
bool operator()(int left, const std::unique_ptr<int>& right) const
{ return left < *right; }
};
auto t = std::binary_search(begin, end, val, Compare{});