2

There must be a trivial answer to this...

I have a std::set or a std::map or some object type which has a natural ordering - say std::less.

I need to change my set or map to contain shared_ptr instead of copies of T.

So I want something like:

using my_set std::set<std::shared_ptr<T>, std::less<*T>>;

But I'm drawing a blank as to how to specify "use the less adaptor on ____ adaptor of T so that it's on dereferenced members, not on shared_ptrs!"

Is there a std::less<std::dereference<std::shared_ptr<T>>> equivalent?

Mordachai
  • 9,412
  • 6
  • 60
  • 112

3 Answers3

2

There is currently no functor in the C++ standard library to achieve what you want. You can either write a custom comparator, or if you need this functionality often, come up with an indirect/dereference function object.

Related and potentially helpful threads; the first one offers a generic solution for many operators (even if it requires a bit of code):

Community
  • 1
  • 1
TheOperator
  • 5,936
  • 29
  • 42
  • Thank you. These look promising to help understand the issue and why this corner of C++ is still a major PIA. – Mordachai Oct 10 '16 at 14:54
2

While the standard library may not already provide what you need, I think it's pretty trivial to write your own std::dereference_less:

#include <memory>
#include <set>

namespace std
{
    template<typename T>
    struct dereference_less
    {
        constexpr bool operator ()(const T& _lhs, const T& _rhs) const
        {
            return *_lhs < *_rhs;
        }
    };
}

int main()
{
   using key_type = std::shared_ptr<int>;
   std::set<key_type, std::dereference_less<key_type>> mySet;
}

Demo (refactored a bit to have a template type alias like in your question)

AndyG
  • 39,700
  • 8
  • 109
  • 143
1

Since you are already changing your internal interface to something that requires dereferencing you could also just write a wrapper class and provide a bool operator< () as follows:

#include <memory>   // shared_ptr
#include <set>      // set
#include <iostream> // cout
using namespace std;

template<typename T>
class wrapper
{
public:
  shared_ptr<T> sp;

  bool operator< (const wrapper<T>& rhs) const
  {
    return  *( sp.get() ) < *( rhs.sp.get() ) ;
  }
  wrapper(){}
  wrapper(shared_ptr<T> sp):sp(sp){}
};

int main()
{
  shared_ptr<int> sp1 (new int);
  *sp1 = 1;
  shared_ptr<int> sp2 (new int);
  *sp2 = 2;

  set<wrapper<int>> S;
  S.insert(wrapper<int>(sp2));
  S.insert(wrapper<int>(sp1));

  for (auto& j : S)
    cout << *(j.sp) << endl;

  return 0;
}
VCSEL
  • 402
  • 3
  • 6