c++c++17comparatorstdset

How to use a std::set as a data member with an explicit comparator member function?


I am using C++17.

std::set is a template type:

template<
    class Key,
    class Compare = std::less<Key>,
    class Allocator = std::allocator<Key>
> class set;

One can have a std::set as a data member. For example:

#include <set>

class Foo
{
    std::set<size_t> someSet_;
};

One can also explicitly specify the comparison function. For example:

#include <set>

auto compare = [](size_t index1, size_t index2) {
    return index1 < index2;
};

class Foo
{
public:
    Foo() : someSet_(compare)
    {
    }

private:
    std::set<size_t, decltype(compare)> someSet_;
};

Now, suppose that the comparison function is a member function. For example:

#include <set>
#include <vector>

class Foo
{
public:
    Foo() : someSet_(compare) // does not compile
    {
    }

private:
    bool compare(size_t index1, size_t index2) const
    {
        return someVector_[index1] < someVector_[index2];
    }

    std::vector<int> someVector_;
    std::set<size_t, decltype(compare)> someSet_; // does not compile
};

As commented, this last code does not compile.

How could someSet_ be declared and initialized to use Foo::compare()?


Solution

  • If you look at errors generated by compiler, you will see, that compare can't be non-static function. So, usually you do static function. But in your case you need access to member variable, in this case its better to create helper comparator object. For example, like this:

    #include <set>
    #include <vector>
    
    class Foo
    {
    public:
        Foo()
        {
        }
    
    private:
        struct comparator {
            comparator(const Foo& foo) : foo_(foo) {}
            bool operator()(size_t index1, size_t index2) const
            {
                return foo_.someVector_[index1] < foo_.someVector_[index2];
            }
        private:
            const Foo& foo_;
        };
    
        std::vector<int> someVector_;
        comparator comp_{*this};
        std::set<size_t, comparator> someSet_{comp_};
    };
    

    PS: But in this case you need to define or delete copy/move constructors and assignment operators, since default will incorrectly copy such comparator.