Вот как прочитать сообщения об ошибках:
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = node]’:
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_tree.h:1141: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = node, _Val = std::pair<const node, bool>, _KeyOfValue = std::_Select1st<std::pair<const node, bool> >, _Compare = std::less<node>, _Alloc = std::allocator<std::pair<const node, bool> >]’
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_map.h:469: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::pair<const _Key, _Tp> >::other>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::insert(const std::pair<const _Key, _Tp>&) [with _Key = node, _Tp = bool, _Compare = std::less<node>, _Alloc = std::allocator<std::pair<const node, bool> >]’
prog.cpp:15: instantiated from here
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_function.h:230: error: no match for ‘operator<’ in ‘__x < __y’
Во-первых, мы игнорируем большинство строк 'instantiated from', потому что они просто говорят о том, как расширились шаблоны.Важным является последний, ссылающийся на наш исходный код, потому что он сообщает нам, где произошла ошибка.Конечно, мы все равно знали об этом, поэтому пропустим и это.Мы также проигнорируем путь к рассматриваемому заголовку библиотеки, потому что нам все равно, как компилятор хранит свои вещи.
stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = node]’:
stl_function.h:230: error: no match for ‘operator<’ in ‘__x < __y’
Итак ... наш код косвенно вызывает ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = node]’
, илиесли мы действительно сделаем эту замену, ‘bool std::less<node>::operator()(const node&, const node&) const’
.И это проблема, потому что в реализации std::less
есть no match for ‘operator<’ in ‘__x < __y’
.
__x
и __y
- переменные (вы должны быть в состоянии догадаться об этом).Исходя из названия, мы можем догадаться (и если бы мы изучали стандартную библиотеку, мы бы знали), что std::less
- это функция шаблона, которая сравнивает две вещи одного и того же типа и возвращает значение того, меньше ли первое второе, чем второе.
Как это происходит?Конечно, используя operator<
.Вот что нам нужно сделать, чтобы решить проблему: в нем говорится, что operator<
не для того, что сравнивается, поэтому мы должны его предоставить.Что сравнивается?node
с, конечно.Итак, мы определяем operator<
для нашего класса.
Почему он это делает?Таким образом, мы можем написать функции, которые принимают операцию сравнения в качестве аргумента (либо шаблонный аргумент, либо параметр времени выполнения - но первый гораздо более распространенный), и передают std::less
.Вот причина существования std::less
: оно превращает процесс сравнения вещей в функцию, а реальные функции несколько более полезны.
Насколько это актуально?Потому что, как говорили другие, std :: map фактически передает std::less
в качестве аргумента.На самом деле это аргумент по умолчанию для шаблона std::map
, который используется для сравнения элементов.В конце концов, часть интерфейса карты состоит в том, что каждый ключ уникален.Как вы собираетесь проверять ключи на уникальность, если не можете их сравнить?Конечно, технически вам нужно будет только сравнить их на равенство, чтобы это работало.Но оказывается, что возможность заказа ключей позволяет создать гораздо более эффективную структуру данных.(Вы бы знали об этом, если бы вы действительно проходили курсы в университете по программированию и CS.)
Почему не было проблемы с int
?Теперь вы должны догадаться: operator<
уже естественно работает для int
с.Но вы должны сказать C ++, как это сделать для любых пользовательских типов, потому что вы можете иметь в виду что-то еще.