Reputation: 5830
Are there any proper means in the C++11 STL to store object pointers in a std::set
, and have them sorted properly by the object's operator <
method?
There is, of course, the possibility of writing my own Compare
type and passing that to the set
as its second template argument, but I'd imagine that the STL would provide a much more convenient way.
A bit of googling revealed std::reference_wrapper
, which in my opinion should allow code like this:
#include <functional>
#include <set>
struct T {
int val;
bool operator <(T& other) {
return (this->val < other.val);
}
};
int main() {
std::set<std::reference_wrapper<T>> s;
T a{5};
s.insert(a);
}
But in fact, this causes a compiler error:
clang++ -std=c++11 -Wall -Wextra -pedantic test.cpp -o test
In file included from test.cpp:1:
In file included from /usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:49:
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/stl_function.h:235:20: error: invalid operands to binary expression ('const std::reference_wrapper<T>'
and 'const std::reference_wrapper<T>')
{ return __x < __y; }
~~~ ^ ~~~
(the gcc error is similar, but a lot longer)
Upvotes: 5
Views: 2046
Reputation: 860
The right approach is to create a specialized std::less
for our MyStruct.
namespace std
{
template<> struct less<MyStruct>
{
bool operator() (const MyStruct& lhs, const MyStruct& rhs) const
{
return lhs.a < rhs.a;
}
};
}
Remember std::set
uses std::less
by default to compare two elements.
Defined in header <set>
template<
class Key,
class Compare = std::less<Key>,
class Allocator = std::allocator<Key>
> class set;
https://en.cppreference.com/w/cpp/container/set
Upvotes: 0
Reputation: 227390
You need to make your less-than operator a non-member, and give it const
reference parameters:
struct T {
int val;
};
bool operator <(const T& lhs, const T& rhs) {
return (lhs.val < rhs.val);
}
This allows for implicit conversions on from std::reference_wrapper<T>
to T
on both LHS and RHS of the <
operator, whereas the member version only allows for an implicit conversion on the RHS. Symmetry between LHS and RHS of binary operators is one of the classic arguments for implementing them as non-members.
Upvotes: 6
Reputation: 1921
The object a method is called on cannot be implicitly converted, so you need to implement comparison as a free function to use the conversion from reference_wrapper<T> to T.
Upvotes: 2