Почему это работает? std :: set find с ключом поиска и настраиваемым компаратором

Я не понимаю, почему работает следующее (хотя я рад, что это работает!):

Я могу определить std::set объектов с помощью настраиваемого компаратора. Этот настраиваемый компаратор работает путем сравнения некоторых переменных-членов двух сравниваемых объектов. НО тогда я могу использовать функцию set .find(x), где x относится к типу переменной-члену, а не к самому объекту, и это работает!

Вот чрезвычайно упрощенный пример:

my_class.h

class my_class   //just hold an integer
{
    public:
      int an_int;

    my_class(int new_int) : an_int(new_int)
    { }


    //compare instances of this class by comparing their integers...
    struct compare_instances   
    {    
      bool operator() (const my_class &a, const my_class &b) const
      {
        return a.an_int < b.an_int;
      }
    };
};

main.cpp:

...
std::set<my_class, my_class::compare_instances> my_class_set;
my_class_set.insert( my_class(18) );
my_class_set.insert( my_class(7)  );
my_class_set.insert( my_class(22) );

std::set<my_class, my_class::compare_instances>::const_iterator found_it
                  = my_class_set.find(18);
 std::fprintf(stderr, "found_it->an_int = %d\n", found_it->an_int); 

Вывод: "found_it-> an_int = 18" !!!!!!

Я ожидал, что приведенный выше код не будет компилироваться, и компилятор закричит мне, что «18 не относится к типу my_class». Но это не так ...

Разве аргументы .find не должны быть того же типа, что и элементы самого set? Вот что, кажется, говорится в документации ...


person cmo    schedule 28.02.2012    source источник
comment
посмотрите на свой конструктор: my_class(int new_int). вы можете создать my_class, начиная с int. попробуйте find("blah"), и он не скомпилируется :)   -  person vulkanino    schedule 28.02.2012


Ответы (1)


Это работает, потому что int неявно преобразуется в ваш класс. Любой конструктор, который не отмечен explicit и может быть вызван ровно с одним аргументом, который не относится к типу самого класса, определяет неявное преобразование. Фактически это означает, что всякий раз, когда ожидается объект типа класса, вы также можете использовать int, и он будет автоматически преобразован.

person Björn Pollex    schedule 28.02.2012
comment
Хорошо, вы добавили все мои баллы к своему ответу. Я удаляю другие свои комментарии. 8v) - person Fred Larson; 28.02.2012
comment
@FredLarson, даже если он не связан, порекомендуете ли вы всегда объявлять явные кострукторы? - person vulkanino; 28.02.2012
comment
@vulkanino: Если вы не хотите неявного преобразования, это может быть неплохой идеей. Мне не известно о каких-либо проблемах с добавлением explicit в конструктор, даже если он не может использоваться для неявного преобразования. - person Fred Larson; 28.02.2012
comment
вауауау, мило, какая тонкая деталь. Как вы думаете, это хорошая практика? Это, безусловно, упрощает задачу - у меня может быть set объектов для поиска по целому числу (благодаря неявному конструктору). Но, конечно, неявный конструктор строит весь объект для поиска ... что расточительно. Есть лучший способ сделать это? Искать мои предметы в наборе? Я могу использовать map, где ключом является потенциальная переменная-член для компаратора ... но это добавляет уровень сложности. - person cmo; 28.02.2012
comment
@CycoMatto: Этот вопрос касается с этой проблемой. - person Björn Pollex; 28.02.2012