#c #iterator #compiler-errors #constants
#c #итератор #ошибки компилятора #константы
Вопрос:
Итак, у меня есть функция find, которая имеет две версии:
template <typename T>
typename btree<T>::iterator btree<T>::find(const Tamp; elem)
{
//Implementation
}
а другая — версия const_iterator:
template <typename T>
typename btree<T>::const_iterator btree<T>::find(const Tamp; elem) const
{
//Implementation
}
В моем тестовом файле, когда я делаю
btree<char>::iterator it = myTree.find('M');
Все работает нормально, однако, когда я использую версию const_iterator:
btree<char>::const_iterator it = myTree.find('M');
Это выдает ошибку
ошибка: запрошено преобразование из ‘btree_iterator’ в нескалярный тип ‘const_btree_iterator’
Что, очевидно, означает, что find использует только версию итератора (не const
). Я знаю, что C должен вызывать const_iterator
версию автоматически — если я все сделал правильно. Итак, вопрос в том, что я могу делать неправильно?
Классы итераторов:
class btree_iterator
и class const_btree_iterator
которая является просто копией вставки btree_iterator
с измененными именами
Вот полный исходный код:
btree_iterator.h (включает const_btree_iterator) http://pastebin.com/zQnj9DxA
btree.h http://pastebin.com/9U5AXmtV
btree.tem http://pastebin.com/U9uV3uXj
Комментарии:
1. Видны ли как постоянные, так и неконстантные версии итератора btree при вызове myTree.find ? можете ли вы опубликовать весь файл?
2. Отредактировал вопрос со ссылками на исходный код
Ответ №1:
Все стандартные контейнеры реализуют преобразование неконстантных итераторов в постоянные (как указано в требованиях к концепции контейнера):
Тип итератора, используемого для перебора элементов контейнера. Ожидается, что тип значения итератора будет типом значения контейнера. Должно существовать преобразование из типа итератора в тип итератора const.
Вам нужен конструктор преобразования следующим образом:
class btree_iterator;
class const_btree_iterator
{
// ....
public:
const_btree_iterator(const btree_iteratoramp; rhs) { /* .... */ }
//optionally: const_btree_iteratoramp; operator=(const btree_iteratoramp; rhs) { /* .... */ }
};
Я также добавил оператор присваивания, но я полагаю, что он избыточен
Комментарии:
1. Спасибо! Это сработало, и я действительно думал, что C каким-то образом просто вызовет правильную версию find , но я полагаю, что это не так
2. Нет. Единственное место, где я знаю, что «разрешение перегрузки», по-видимому, возвращается и продолжает попытки в C , — это знаменитое правило SFINAE (на самом деле оно не игнорирует перегрузки: оно игнорирует неудачные экземпляры шаблонов)
Ответ №2:
Важным моментом здесь является то, что разрешение перегрузки выполняется только на основе аргументов функции, а не результата. В вашем конкретном случае у вас есть две разные перегрузки, и разница в том, что this
в одной из них неявное значение является постоянным, эта перегрузка будет обнаруживаться всякий раз, когда статический тип объекта или ссылки, для которых вызывается метод, является постоянным.
Если вы хотите принудительно отправить постоянную перегрузку, вы можете получить ссылку const, а затем вызвать эту ссылку:
btree<char> const amp; r = myTree;
btree<char>::const_iterator it = r.find('M');
Вам следует избегать этой конструкции в реальном коде, даже если вы используете ее для целей тестирования. Причина в том, что постоянные и неконстантные перегрузки должны иметь одинаковую семантику и, следовательно, поведение должно быть одинаковым.
Также обратите внимание, что в стандартных контейнерах существует неявное преобразование из iterator
в const iterator
для поддержки использования const_iterator
s непосредственно в неконстантных контейнерах. Вы должны сделать то же самое, то есть, если вы предоставляете неявное преобразование из iterator
в const_iterator
, тогда вы можете просто написать:
btree<char>::const_iterator it = myTree.find('M');
… и это будет работать (не будет тестировать find
метод, но позволит вам проверить const_iterator
поведение)
Комментарии:
1. Спасибо за это, я исправил это, используя преобразование из iterator в const_iterator, как вы упомянули
2. @Arvin Мне было неясно, означало ли в моем тестовом файле , что вы пытались протестировать
find
перегрузку constconst_iterator
или просто контейнер в целом.3. «в моем тестовом файле» означало внутри основной функции в отдельном cpp-файле, который проверяет мою реализацию класса btree. Я на самом деле тестировал контейнер в целом и наткнулся на эту проблему