Объявление семантического итератора?

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

Скажем, у меня есть это:

std::list<std::string> msgs;

for (std::list<std::string>::iterator it = msgs.begin(); it < msgs.end(); it++) {
    // ...
}

Для меня это трудно прочитать. std::list<std::string>::iterator почти похоже на магическое число, особенно если объявление msgs далека, как в файле заголовка. ИМО было бы легче читать и гораздо более семантично, если бы это было примерно так:

std::list<std::string> msgs;

for (msgs.iterator it = msgs.begin(); it < msgs.end(); it++) {
    // ...
}

Теперь это явно незаконно С++. Но мой вопрос в том, есть ли способ реализовать что-то, что поддерживает запись объявлений итератора, как это?

Ответ 1

Если вы предоставите typedef, это сделает жизнь намного проще:

typedef std::list<std::string>::iterator ListIterator;
for( ListIterator it = msgs.begin(); it != msgs.end(); ++it ){}

Кроме того, С++ 0x делает это за вас, предоставив ключевое слово auto:

for( auto it = msgs.begin(); it != msgs.end(); ++it ){}

редактируйте, как через 5 лет после даты, но я обновил < tp != и использовал preincrement, потому что на самом деле то, что я делал целую вечность, и имеет больше смысла для меня, до такой степени, что мне интересно, как Я когда-либо писал этот ответ, не используя этот

Ответ 2

Существуют два практических, канонических подхода:

typedef std::list<int> list_t;
list_t l;

// later:
for (list_t::iterator it = l.begin(), end = l.end(); it != end; ++it) {}

И только С++ 0x-only auto:

std::list<int> l;

// later:
for (auto it = l.begin(), end = l.end(); it != end; ++it) {}

Кроме того, С++ 0x позволяет:

std::list<int> l;

// later:
for (decltype(l)::iterator it = l.begin(), end = l.end(); it != end; ++it)
   std::cout << *it << ", ";

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

Недостатком является то, что возможность применения оператора области (::) к decltype ссылка был только проголосован в рабочем документе сравнительно недавно, и я не знаю каких-либо компиляторов, которые его поддерживают (GCC 4.5.1 не).

Ответ 3

Вы можете использовать typedef для очистки:

typedef std::list<std::string>::iterator string_iterator;

std::list<std::string> msgs;

for (string_iterator it = msgs.begin(); it != msgs.end(); it++) {
    // ...
}

Ответ 4

Все контейнеры имеют эти typedef, чтобы включить запись очень общего кода. Рассмотрим следующий шаблон функции:

template<class T>
void foo(const T& container) {
    for(T::const_iterator it = T.begin(); it != T.end(); it++) {
        // do stuff
    }
}

Это позволяет вам писать код, который может работать с любым объектом, который определяет тип const_iterator и метод begin() и end().

В С++ 0x проблема решена с введением ключевого слова auto:

for(auto it = container.begin(); it != container.end(); it++) {
    // do stuff
}

Ответ 5

Каноническое решение

std::for_each(msgs.begin(), msgs.end(), ... );

До С++ 0x запись бит ... была немного сложной (если это было что-то сложное), но теперь у нас есть лямбда.