std :: list итератор: получить следующий элемент - PullRequest
9 голосов
/ 23 апреля 2010

Я пытаюсь построить строку, используя элементы данных, хранящиеся в std :: list, где я хочу, чтобы запятые помещались только между элементами (т. Е. Если в списке есть элементы {A, B, C, D}, Строка должна быть "A, B, C, D".

Этот код не работает:

typedef std::list< shared_ptr<EventDataItem> > DataItemList;
// ...
std::string Compose(DataItemList& dilList)
{
    std::stringstream ssDataSegment;
    for(iterItems = dilList.begin();
        iterItems != dilList.end(); 
        iterItems++)
    {
        // Lookahead in list to see if next element is end
        if((iterItems + 1) == dilList.end())  
        {
            ssDataSegment << (*iterItems)->ToString();
        }
        else
        {
            ssDataSegment << (*iterItems)->ToString() << ",";
        }
    }
    return ssDataSegment.str();
}

Как мне получить "the-next-item" в списке std :: list с помощью итератора? Я ожидаю, что это связанный список, почему я не могу получить следующий пункт?

Ответы [ 6 ]

15 голосов
/ 23 апреля 2010

Вы не можете сделать it + N, потому что у вас нет произвольного доступа к итераторам списка.Вы можете сделать только один шаг за раз с итераторами списка (это двунаправленные итераторы).

Вы можете использовать boost::next и boost::prior

// Lookahead in list to see if next element is end
if(boost::next(iterItems) == dilList.end())  
{

Или вы можете напечатать запятую раньше:

std::string Compose(DataItemList& dilList)
{
    std::stringstream ssDataSegment;
    for(iterItems = dilList.begin();
        iterItems != dilList.end(); 
        ++iterItems)
    {
        if(iterItems != diList.begin())
            ssDataSegment << ",";
        ssDataSegment << (*iterItems)->ToString();
    }
    return ssDataSegment.str();
}
12 голосов
/ 23 апреля 2010

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

Чтобы получить следующий итератор, сделайте копию и увеличьте ее.

6 голосов
/ 23 апреля 2010

Другое решение состоит в том, чтобы первая запись представляла собой особый случай, а не последнюю запись:

std::string Compose(DataItemList& dilList)
{
    std::stringstream ssDataSegment;
    for(iterItems = dilList.begin();
        iterItems != dilList.end(); 
        ++iterItems)
    {
        // See if current element is the first
        if(iterItems == dilList.begin())  
        {
            ssDataSegment << (*iterItems)->ToString();
        }
        else
        {
            ssDataSegment << "," << (*iterItems)->ToString();
        }
    }
    return ssDataSegment.str();
}
2 голосов
/ 23 апреля 2010

Вы можете полностью избежать этой проблемы, используя:

std::string Compose(DataItemList& dilList)
{
    std::stringstream ssDataSegment;
    for(iterItems = dilList.begin(); iterItems != dilList.end(); iterItems++)
    {
        ssDataSegment << (*iterItems)->ToString() << ","; // always write ","
    }
    std::string result = ssDataSegment.str();
    return result.substr(0, result.length()-1); // skip the last ","
}

Сначала вы пишете «,» для всех элементов (даже для последнего).Затем вы удаляете ненужные последние ",", используя substr.Это дополнительно приводит к более четкому коду.

1 голос
/ 15 января 2015

Примечание: начиная с C ++ 11 вы можете использовать std :: next и std :: prev .

1 голос
/ 23 апреля 2010

Еще одна возможность:

#include "infix_iterator.h"
#include <sstream>

typedef std::list<shared_ptr<EventDataItem> > DataItemList;

std::string Compose(DataItemList const &diList) {
    std::ostringstream ret;
    infix_ostream_iterator out(ret, ",");

    for (item = diList.begin(); item != diList.end(); ++item)
        *out++ = (*item)->ToString();
    return ret.str();
}

Вы можете получить infix_iterator.h из архива Google Usenet (или различных веб-сайтов).

...