STL как ярлык для контейнера typedef?

Обычный паттерн с контейнерами STL таков:

map<Key, Value> map;
for(map<Key, Value>::iterator iter = map.begin(); iter != map.end(); ++iter)
{
  ...
}

Итак, чтобы не писать объявление параметров шаблона, мы можем сделать это где-нибудь:

typedef map<Key, Value> TNiceNameForAMap;

Но если эта карта используется только в одной функции или для одной итерации, это неприятные накладные расходы.

Есть ли способ обойти этот typedef?


person shoosh    schedule 24.09.2008    source источник


Ответы (7)


Не уверен, что вы имеете в виду под "накладными расходами". Если это упрощает способ написания кода, используйте его, в противном случае придерживайтесь полного текста.

Если он используется только в ограниченной области, поместите определение типа в ту же область. Тогда его не нужно публиковать, документировать или отображать на каких-либо схемах UML. Например (и я не утверждаю, что это лучший код в других отношениях):

int totalSize() {
    typedef std::map<Key, Value> DeDuplicator;
    DeDuplicator everything;

    // Run around the universe finding everything. If we encounter a key
    // more than once it's only added once.

    // now compute the total
    int total = 0;
    for(DeDuplicator::iterator i = everything.begin(); i <= everything.end(); ++i) {
        total += i->second.size(); // yeah, yeah, overflow. Whatever.
    }
    return total;
}

В сочетании с предложением Ферруччо (если вы используете ускорение) цикл становится:

BOOST_FOREACH(DeDuplicator::pair p, everything) {
    total += p.second.size();
}

И в сочетании с предложением bk1e (если вы используете C ++ 0x или у вас есть функции из него) и предполагая, что BOOST_FOREACH взаимодействует с auto так, как я думаю, это должно быть основано на том факте, что он обычно может обрабатывать неявное приведение к совместимым типам :

std::map<Key, Value> everything;
// snipped code to run around...
int total = 0;
BOOST_FOREACH(auto p, everything) {
    total += p.second.size();
}

Неплохо.

person Steve Jessop    schedule 24.09.2008
comment
Отличная работа ! Ваш последний находится на уровне Python по компактности и читабельности. - person rlerallut; 26.09.2008

Вы можете использовать Boost.Foreach.

person Ferruccio    schedule 24.09.2008
comment
Хороший прием, поскольку подробность цикла в любом случае больше, чем подробность определения типа ... - person Steve Jessop; 24.09.2008
comment
Да, и самая лучшая часть - это синтаксис, достаточно похожий на конструкцию C ++ 0x foreach, чтобы вы могли обновлять свой код с помощью поиска и замены регулярного выражения, если ваш компилятор поддерживает это. - person Ferruccio; 26.09.2008

Будущая версия стандарта C ++ (известная как C ++ 0x) будет представить новое использование ключевого слова auto, что позволит вам что-то написать вроде следующего:

map<Key, Value> map;
for(auto iter = map.begin(); iter != map.end(); ++iter)
{
  ...
}
person bk1e    schedule 24.09.2008
comment
Woohoo! Сильная типизация, как должно быть. - person Steve Jessop; 24.09.2008

Лично я считаю, что MYMAP :: iterator более читабелен, чем map ‹int, string› :: iterator или даже std :: map ‹int, std :: string ›:: iterator, поэтому я всегда использую typedef. Единственные накладные расходы - это одна строка кода.

После компиляции кода разницы в размере или скорости исполняемого файла не будет. Дело просто в удобочитаемости.

person Adam Pierce    schedule 24.09.2008

Если typedef является локальным для одной функции, ему даже не нужно быть красивым именем. Используйте X или MAP, как в шаблоне.

person Zan Lynx    schedule 24.09.2008
comment
У переменных тоже не обязательно должны быть красивые имена. Но хорошо, если они это сделают ;-) - person Steve Jessop; 24.09.2008

C ++ 0x также будет предлагать цикл for на основе ранжирования, который аналогичен итеративному циклу для других языков.

К сожалению, GCC еще не поддерживает диапазон для (но действительно реализует auto).

Изменить: тем временем также подумайте о типе итератора. Он не обходит одноразовый typedef (если вы не помещаете его в заголовок, который всегда является вариантом), но он делает результирующий код короче на один :: iterator.

person coppro    schedule 24.09.2008

За последние несколько лет я действительно попытался отойти от написанных вручную циклов вместо использования алгоритмов STL. Ваш приведенный выше код можно изменить на:

struct DoLoopBody {
  template <typename ValueType>
  inline void operator()(ValueType v) const {
    // ...
  }
};

std::for_each (map.begin(), map.end(), DoLoopBody ());

К сожалению, класс DoLoopBody не может быть локальным классом, что часто отмечается как недостаток. Однако я считаю это преимуществом в том, что теперь тело цикла можно тестировать отдельно.

person Richard Corden    schedule 24.09.2008
comment
Проблема с этим (и я не обвиняю вас в его использовании, я обвиняю STL) в том, что на самом деле это не цикл foreach, потому что вы указываете начальные и конечные условия. Это больше похоже на оператор диапазона Perl .. - person Steve Jessop; 24.09.2008
comment
Также обратите внимание, что будущий стандарт C ++ 0x будет включать что-то похожее на лямбда-функции, что сделает код более компактным (хотя и не более удобным для чтения, IMHO). Хороший аргумент в отношении изолированного тестирования тела цикла. - person rlerallut; 25.09.2008