Каково соглашение об именах, когда typdef сложные карты STL? - PullRequest
12 голосов
/ 17 апреля 2009

1) Какое соглашение используется на практике при typedef'ing

что-то вроде

typedef std::map<SomeClass*, SomeOtherClass>  [SomeStandardName>]
typedef std::map<SomeClass*, std<SomeOtherClass> >  <[SomeStandardName]

2) Где вы обычно размещаете заголовочные файлы typedef: глобально, локально для класса?

3) Вы печатаете итераторы или const map <> version?

4) Скажем, у вас есть карта, которая используется двумя разными понятиями, вы создаете два отдельных typedefs для них?

typedef map<string, SomeClass *> IDToSomeClassMap;
typedef map<string, SomeClass *> DescriptionToSomeClassMap;

Спасибо


Редактировать # 1

Меня особенно интересуют карты typedef STL, такие как

typedef map<int, string> IdToDescriptionMap

или

typedef map<int, string> IdToDescription

Что такое обычные практики?

Ответы [ 9 ]

16 голосов
/ 17 апреля 2009

Я предпочитаю следующее соглашение:

typedef std::map< Foo, Bar > FooToBarMap

Я намеренно избегаю typedef'ов итераторов, я предпочитаю явно ссылаться на них как:

FooToBarMap::const_iterator

Поскольку итераторы уже являются де-факто стандартным именем типа. Я считаю, что FooToBarMapConstIter на самом деле менее понятен для чтения при скимминге кода.

2 голосов
/ 17 апреля 2009

Общепринятых правил в отношении этих имен не существует. Обычно я использую имя класса «value» с суффиксом Map. В вашем примере это будет SomeOtherClassMap . Я использую это соглашение, потому что обычно более интересно, что ваша карта содержит объекты «значения» типа SomeOtherClass , а затем вы ищете их с «ключами» SomeClass .

1 голос
/ 19 апреля 2009

Вторая часть вопроса для меня самая интересная. Я предпочитаю помещать typedef в классы, которые их используют, когда для них есть логическое место, даже если они используются в других классах. Но это вызывает некоторые проблемы с предварительными объявлениями (которые мы интенсивно используем для скорости компиляции).

Например, в одном недавнем проекте у нас был класс с именем Io со встроенным typedef с именем Point, который предназначен для очень читабельного кода - Io::Point очень понятный и читаемый. Но всякий раз, когда мы хотели использовать тип, мы должны были включать объявление класса Io, даже если все, что нам было нужно, это объявление Io::Point, так как нет никакого способа (о котором я знаю) для прямого объявления тип, который находится внутри заранее объявленного класса.

В этом случае мы закончили с этим обоими способами. Мы создали глобальный тип IoPoint, а затем typedef d Io::Point (так что наш уже написанный код не нужно было изменять). Не самый красивый ответ, но он сделал свою работу.

Что касается других частей:

Мы не используем никаких специальных соглашений для имен. Для карт мы часто используем * DescriptiveSomething *** Map ** (поскольку маловероятно, что мы когда-либо изменится с карты на какой-либо другой тип контейнера), но если DescriptiveSomething достаточно наглядно и не конфликтует с существующим именем, мы часто будем его использовать.

Как правило, мы не беспокоимся о создании typedef для итераторов, поскольку легко (и очень легко читаемо) просто использовать Type::iterator или Type::const_iterator. Тем не менее, мы делаем иногда печатаем их по умолчанию, если имя типа настолько длинное, что Type::const_iterator делает код слишком "коротким". (Не знаю лучшего способа сказать это, но вы, наверное, знаете, о чем я.)

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

1 голос
/ 19 апреля 2009

Использование слова «Карта» или «Вектор» в виде бесполезных обозначений. Это слова, связанные с реализацией, а не с бизнес-моделью.

Вам не нужно показывать, что этот тип является вектором или картой. Вы можете использовать список. Как

typedef std::vector<std::string> List;
typedef std::set<std::string> List;

Это оба списка строк. И это правда.

typedef std::map<std::string, Object> List;
or  
typedef std::map<std::string, Object> NamedList;

Суть в том, что я не использую венгерскую нотацию.

0 голосов
/ 17 апреля 2009

Обычно я определяю связанное имя для typedef с указанием типа объекта.

Пример:

typedef std::vector<ClassCompStudent*> StudentCollection;

typedef std::map<std::string /*id*/, ClassCompStudent* /*pStudent*/>  IDToStudentMap;

Кроме того, я определяю их как public в заголовке класса, в котором был создан объект. Это дает мне преимущество в изменении типа контейнера без нарушения кода клиента.

class Test
{
public:
    typedef std::vector<ClassCompStudent*> StudentCollection;

    /* Users of Test need not know whether I use vector or list for 
        storing students. They get student collection and use it*/
    bool getStudents(StudentCollection& studentList) const;

    void print()
    {
        //do printing
    }
private:

    StudentCollection m_StudentList;
};

bool function(const Test& testObj)
{
    //If StudentCollection gets changed to list, this code need not be changed.
    StudentCollection aCollection;
    testObj.getStudents(aCollection);
    std::for_each(aCollection.begin(), aCollection.end(), std::mem_fun(&Test::print));
}
0 голосов
/ 17 апреля 2009

Интересует вопрос:
Я посмотрел в boost, и я вижу, что у них нет каких-либо глобальных правил, но наиболее часто используется соглашение

typedef std::map< key, value > some_domain_specific_name_map;

или

typedef std::map< key, value > some_domain_specific_name_map_type;

также рекомендуется создавать typedef для value_type или итераторов, обычно они имеют то же имя, что и map, но с завершающим _value_type, _iterator.

0 голосов
/ 17 апреля 2009

Мы используем следующее на моем рабочем месте:

typedef std::map WhateverMap;
typedef WhateverMap::iterator WhateverIter;
typedef WhateverMap::const_iterator WhateverCIter;

Что касается местоположения, то оно меняется. Если он специфичен для класса, он может быть в структуре Impl или в защищенной или закрытой области объявления класса. Если он более общий (используется для файлов, используется в API), мы помещаем его в отдельный заголовок стиля "FooTypes.h".

Обратите внимание, что, поскольку мы часто меняем базовый тип, мы можем использовать «WheverCollection» вместо «WheverVec» или «WheverList». Нередко бывает, что «WheverList» фактически определяется по типу для вектора или слайса, в зависимости от требуемой площади и характеристик производительности.

0 голосов
/ 17 апреля 2009

Нет, просто имейте в виду общие правила именования идентификаторов (нет _ для начала и т. Д.). Кроме того, если в вашей организации есть руководство по кодированию, лучше всего придерживаться его.

Часто, когда вы определяете свой собственный шаблонный класс, он становится беспорядочным без typedefs - поэтому я бы создал их там как удобные ярлыки. Однако, если это действительно куча классов, я бы предпочел, чтобы это было на уровне namespace.

0 голосов
/ 17 апреля 2009

Я не знаю, существуют ли какие-либо формальные правила по этому вопросу, но я обычно добавляю определения типов в месте, наиболее подходящем для использования в проекте.

  • Если typedef используется только в одном классе, тогда добавьте typedef в определение класса
  • Если typedef используется несколькими несвязанными классами, добавьте его в заголовочный файл на уровне области пространства имен

Что касается фактического имени типа typedef'd. Я называю это тем, что имеет смысл для typedef. Я не даю именам typedef никаких специальных соглашений, таких как префикс _t или что-то в этом роде. Например

typedef stl::map<stl::string,Student> NameToStudentMap;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...