непонятки с const функциями
От: K13 http://akvis.com
Дата: 24.10.07 09:22
Оценка:
есть код:
#include <list>

template< typename T >
class Foo
{
public:
  class iterator
  {
  public:
    iterator& operator++() { return *this; }
    bool operator!=( const iterator& ) { return false; }
  };

  class const_iterator
  {
  public:
    const_iterator& operator++() { return *this; }
    bool operator!=( const const_iterator& ) { return false; }
  };


  iterator begin() { return iterator(); }
  iterator end()   { return iterator(); }

  const_iterator begin() const { return const_iterator(); }
  const_iterator end()   const { return const_iterator(); }

};


int main( int, char** )
{
//  typedef std::list<int> test_t;
  typedef Foo<int> test_t;

  test_t t;
  for ( test_t::const_iterator i = t.begin(), e = t.end(); i !=e; ++i )
    ;

  return 0;
}


при компиляции и GCC и MSVC8 выдают ошибку:
$ g++ m3.cpp
m3.cpp: In function `int main(int, char**)':
m3.cpp:37: error: conversion from `Foo<int>::iterator' to non-scalar type `Foo<int>::const_iterator' requested
m3.cpp:37: error: conversion from `Foo<int>::iterator' to non-scalar type `Foo<int>::const_iterator' requested

при замене с Foo<int> на std::list<int> все компилируется на ура.

Внимание, вопрос -- неужели все дело в том, что в стандартных хидерах есть преобразование из iterator в const_iterator? У msvc итератор вообще наследуется от константного...

Мой реальный класс гораздо сложнее, и мне очень не хочется в цикле
  for ( test_t::const_iterator i = t.begin(), e = t.end(); i !=e; ++i )


допускать появление неконстантного итератора, указывающего на начало списка.

Или я чего-то не понимаю с const — функциями?
Как компилятор выбирает, какую функцию дернуть -- const или не-const?
Почему в данном случае он игнорирует
  const_iterator begin() const { return const_iterator(); }
  const_iterator end()   const { return const_iterator(); }
?
Re: непонятки с const функциями
От: Lorenzo_LAMAS  
Дата: 24.10.07 09:34
Оценка:
У тебя типы iterator и const_iterator никак не связаны. Как же, по-твоему, можно допустить подобное преобразование?
Со стандартными контейнерами проблем не будет. С твоими собственными — ну так решай сам, как делать. Либо воспользуйся наследованием iterator от const_iterator, либо добавь какие-то конструкторы, либо явно различай по имени константные/неконстантные функции, либо просто в выражении obj.begin() obj должен быть константным, тогда и вызовется константная функция. Непонятно, собственно, что у тебя вызывает затруднения.
Of course, the code must be complete enough to compile and link.
Re: непонятки с const функциями
От: Bell Россия  
Дата: 24.10.07 09:37
Оценка:
Здравствуйте, K13, Вы писали:

...

K13>при замене с Foo<int> на std::list<int> все компилируется на ура.


K13>Внимание, вопрос -- неужели все дело в том, что в стандартных хидерах есть преобразование из iterator в const_iterator? У msvc итератор вообще наследуется от константного...


Да, дело именно в этом.
Смотри 23.1 (Container requirements), таблицу 65
В требованиях к типу iterator есть и такое: convertible to X::const_iterator.


K13>Мой реальный класс гораздо сложнее, и мне очень не хочется в цикле

K13>
K13>  for ( test_t::const_iterator i = t.begin(), e = t.end(); i !=e; ++i )
K13>


K13>допускать появление неконстантного итератора, указывающего на начало списка.

Это поправимо.

K13>Или я чего-то не понимаю с const — функциями?

K13>Как компилятор выбирает, какую функцию дернуть -- const или не-const?
На основании типа объекта.
K13>Почему в данном случае он игнорирует
  const_iterator begin() const { return const_iterator(); }
K13>  const_iterator end()   const { return const_iterator(); }
?

Потому что объект имеет тип test_t. Замени его на const test_t и будет тебе счастье:


test_t t;
const test_t& cr = t;
for ( test_t::const_iterator i = cr.begin(), e = cr.end(); i !=e; ++i )
Любите книгу — источник знаний (с) М.Горький
Re: непонятки с const функциями
От: Lorenzo_LAMAS  
Дата: 24.10.07 09:48
Оценка: 2 (1)
K13>Как компилятор выбирает, какую функцию дернуть -- const или не-const?
K13>Почему в данном случае он игнорирует const_iterator begin() const { return const_iterator(); }
K13> const_iterator end() const { return const_iterator(); }

Здесь имеет место разрешение перегрузки. У тебя две функции begin, неконстантная версия подходит лучше (как и почему — это лучше смотреть в стандарте С++, вкратце, есть неявный аргумент типа Foo & у неконстантного begin и const Foo & у второго, в вызове t.begin(), где t — неконстантный, лучшее соответствие у неконстантной функции)
Of course, the code must be complete enough to compile and link.
Re[2]: непонятки с const функциями
От: K13 http://akvis.com
Дата: 24.10.07 09:52
Оценка:
Спасибо!
Как временный workaround пойдет

Не обращал раньше внимания на пункт стандарта... зря.

Позже буду думать, жить с work-around или сделать по стандарту...
Re[3]: непонятки с const функциями
От: Roman Odaisky Украина  
Дата: 24.10.07 10:23
Оценка: 28 (2)
Здравствуйте, K13, Вы писали:

K13>Позже буду думать, жить с work-around или сделать по стандарту...


Делай итераторы с помощью boost::iterator_fa&#231;ade. Тебе понадобится только объявить функции dereference, equal, increment(, decrement(, advance, distance_to)) и унаследоваться, остальное сделает Boost. Можно объявить изменяемый и неизменяемый итераторы одним шаблонным классом.
До последнего не верил в пирамиду Лебедева.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.