0

I have a class made (among others) of a std::set declared as,

std::set<customPair, decltype(comp)> mySet;

with (defined outside the class),

bool comp (customPair a, customPair b) { return a.first >= b.first}

and,

typedef std::pair<int, int> customPair;

Thus, in my class declaration, I declare mySet with

class Example:
  public:
    std::set<customPair, decltype(comp)> mySet;

when I write (i.e. define) it in my constructor,

Example::Example(){
 mySet(comp);
}

I get the following error:

   .../stl_tree.h:880:7 error: function  returning a function
    key_comp() const

I am wondering why:

std::set<customPair, decltype(comp)> mySet(comp);

does work when, for example declared on the fly in any method, but does fail in my case (within class)?

floflo29
  • 2,261
  • 2
  • 22
  • 45
  • 1
    Initialize `mySet` in the [class member initialization list](https://stackoverflow.com/questions/1711990/what-is-this-weird-colon-member-syntax-in-the-constructor) – NathanOliver Jan 10 '22 at 17:17
  • 1
    instead of fragments you better post a [mcve] – 463035818_is_not_an_ai Jan 10 '22 at 17:18
  • @NathanOliver could you briefly expand what you have in mind :) ? – floflo29 Jan 10 '22 at 17:21
  • Pop quiz: what is `decltype(comp)`? Cheat sheet: it's `bool (customPair, customPair)`. When constructing a `std::set` specifying a comparator type of `bool (CustomPair, CustomPair)`, and taking no further action, has absolutely no chance of arranging things that will result in a specific `comp` function being called to do its task. – Sam Varshavchik Jan 10 '22 at 17:22
  • @floflo29 NathanOliver means for you to use this instead: `Example::Example() : mySet(comp) {}` – Remy Lebeau Jan 10 '22 at 17:25
  • @RemyLebeau No alternative with a regular Example() constructor as shown in the question (i.e. without using an initialization list)? – floflo29 Jan 10 '22 at 17:27
  • 1
    That is a regular constructor? – Alan Birtles Jan 10 '22 at 17:29

1 Answers1

2

The type of decltype(comp) is a function but the std::set comparator needs to be a function pointer or functor. Changing to decltype(&comp) fixes the compilation issue.

You also need to pass an instance of the function pointer to the std::set constructor otherwise it'll be null and will crash when you try to add an element. You can do this either in the initialiser list of each of your constructors:

Example()
:mySet(&comp)
{
}

Or directly in the class when you declare the member:

std::set<customPair, decltype(&comp)> mySet{&comp};

Note that due to a quirk of c++ in mySet(&comp) you can just use mySet(comp) and comp is automatically converted to a function pointer unlike in decltype where this conversion doesn't take place.

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
  • FWIW, the `&` in `mySet{&comp}` is not needed, but it is a nice reminder that it needs a function pointer, not a function object. – NathanOliver Jan 10 '22 at 17:46
  • @NathanOliver yep, I do the same, helps prevent the compiler errors in the various places where it doesn't automatically convert like member function pointers – Alan Birtles Jan 10 '22 at 17:50
  • @AlanBirtles It works thanks. I have rather defined comp as a lambda function `auto comp = []{return...;}` thus `std::set mySet{comp};` does work (without &). A last question: compared to a previous working case (outside class stuff), could you explained why `std::set mySet(comp);` (i.e with parentheses rather than braces) does not work here? – floflo29 Jan 10 '22 at 17:57
  • @floflo29 in class initialisation can only be done with initialisers – Alan Birtles Jan 10 '22 at 18:03
  • @AlanBirtles ok but why the syntax with parentheses fails when set is declared inside a class rather than on the fly (I understand why initializing list does work)? Such as shown in solution 2 in https://stackoverflow.com/questions/2620862/using-custom-stdset-comparator – floflo29 Jan 10 '22 at 18:57
  • 1
    because using parenthesis is not using initialisers. In class initialisation can only be done with initialisers – Alan Birtles Jan 10 '22 at 20:34