-1

As a class member of some class A, I would like to maintain an std::set storing Bs. The set uses a custom comparison object which needs to read a non-static class member, m_t in the example code below, to perform its comparison.

Example code:

class B { ... };

class A {
    struct Comp {
        bool operator()(B b1, B b2) const {
            // ... compares b1 and b2, uses m_t
        }
    };
    std::set<B, Comp> m_set;
    double m_t;
};

Unfortunately this does not compile as understandably we cannot access a non-static member of A within Comp. Is there some other way to achieve this? I would like to avoid making m_t static.

(Some background for context: this is for implementing a sweep line algorithm. Specifically, B implements a function dependent on m_t, where m_t varies between 0 and 1. The functions do not intersect within [0, 1], so the comparisons between Bs never change, thus keeping the std::set valid. With the sweepline at a given m_t, I then need to query with a given value which functions in the set surround it.)

Edit: I had already seen the question this is now marked as a duplicate to, Using custom std::set comparator. The answers there do explain how to make a custom comparator, but have nothing to do with referring to another class member.

Willem3141
  • 69
  • 7
  • The comparator will have to have m_factor inside it, won't it? – user253751 Aug 24 '22 at 12:23
  • Does this help? https://stackoverflow.com/questions/14896032/c11-stdset-lambda-comparison-function – armagedescu Aug 24 '22 at 12:24
  • 1
    I do not understand... "so the comparisons between Bs never change" then why do you need `m_t` for the comparison if it has no impact? – 463035818_is_not_an_ai Aug 24 '22 at 12:26
  • 1
    IMO the duplicate doesn't answer the question. OP is apparently aware of how to make the custom comparator, the question is rather how to refer to the enclosing class instance from inside of a nested class instance – The Dreams Wind Aug 24 '22 at 13:03
  • @463035818_is_not_a_number Because while it indeed does not impact comparisons _between_ `B`s, it does impact the query. The comparisons with the query value should be done for that specific `m_t`. – Willem3141 Aug 24 '22 at 13:06
  • *Does that make sense?* not quite. A set is ordered by using the comparator, you cannot later use eg `set::find` with a different comparator. Maybe I just don't understand what you mean with "query" – 463035818_is_not_an_ai Aug 24 '22 at 13:12
  • @463035818_is_not_a_number Imagine that I insert two functions `y = t` and `y = t + 1` into the set. Then if I set `m_t = 0` and use `std::find` with `y = 1`, I will get `y = t + 1`. If I then set `m_t = 1` and use `std::find` with `y = 1`, I will get `y = t`. – Willem3141 Aug 24 '22 at 15:19
  • `std::set::find` does not work like that. If you mean `std::find` then you can use whatever comparator you like. It does not have to be the one you used for sorting – 463035818_is_not_an_ai Aug 24 '22 at 15:49

1 Answers1

4

Comp is just a C++ class, so you can complement it with any data as needed. E.g. a pointer to the enclosing class instance:

struct A {
    
    struct Comp {
        A *host;
        
        bool operator()(B b1, B b2) const {
            std::cout << host->m_t << std::endl;
            // ...m_t is accessible here
        }
    };
    
    double m_t;
    std::set<B, Comp> m_set{ Comp { this } };
    
};
The Dreams Wind
  • 8,416
  • 2
  • 19
  • 49