Как использовать две функции, одна возвращающая итератор, другая возвращающая const_iterator - PullRequest
7 голосов
/ 24 октября 2011

Итак, у меня есть функция find, которая имеет две версии:

template <typename T> 
typename btree<T>::iterator btree<T>::find(const T& elem)
{
    //Implementation
}

и другая версия const_iterator:

template <typename T> 
typename btree<T>::const_iterator btree<T>::find(const T& 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'

Что, очевидно, означает, что поиск всегда использует версию итератора (не 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

Ответы [ 2 ]

9 голосов
/ 24 октября 2011

Все стандартные контейнеры реализуют преобразование неконстантных в константные итераторы (как , указанное в требованиях к концепции контейнера ):

Тип итератора, используемый для итерациичерез элементы контейнера.Ожидается, что типом значения итератора будет тип значения контейнера. Преобразование из типа итератора в константный тип итератора должно существовать .

Вам нужен конструктор преобразования, например, так:

class btree_iterator;
class const_btree_iterator
{
       // ....
       public:
              const_btree_iterator(const btree_iterator& rhs) { /* .... */ }
//optionally: const_btree_iterator& operator=(const btree_iterator& rhs) { /* .... */ }
};

Я также добавил оператор присваивания, но я думаю, что он избыточен

5 голосов
/ 24 октября 2011

Важным моментом здесь является то, что разрешение перегрузки выполняется только на основе аргументов функции, а не результата.В вашем конкретном случае у вас есть две разные перегрузки, и разница в том, что неявная this постоянна в одной из них, эта перегрузка будет срабатывать всякий раз, когда статический тип объекта или ссылки, для которой вызывается метод, постоянен.

Если вы хотите принудительно настроить диспетчеризацию на постоянную перегрузку, вы можете получить константную ссылку и затем вызвать эту ссылку:

btree<char> const & r = myTree;
btree<char>::const_iterator it = r.find('M');

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

Также обратите внимание, что в стандартных контейнерах существует неявное преобразование из iterator в const iterator для поддержки использования const_iterator непосредственно на неконстантных контейнерах.Вы должны сделать то же самое, то есть, если вы предоставляете неявное преобразование из iterator в const_iterator, тогда вы можете просто написать:

btree<char>::const_iterator it = myTree.find('M');

... и оно будет работать (не будет проверятьfind, но позволит вам проверить поведение const_iterator)

...