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

Time:01-19

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()?

CodePudding user response:

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_;
    };
    friend comparator;

    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 comporator.

CodePudding user response:

The only reason why you would want the comparator to be a member function is when it generates different results depending on the state of the object it's a member of. But that's wrong, the results of the comparator should not change because then the set you're using suddenly has a wrong ordering, and that's not good. For that reason, make sure your comparator is an entirely separate object that has its own state and does not change that state while its in use.

  • Related