Я немного запутался, если и когда я должен использовать typedef в C ++. Я чувствую, что это баланс между читабельностью и ясностью.
Вот пример кода без каких-либо определений типов:
int sum(std::vector<int>::const_iterator first,
std::vector<int>::const_iterator last)
{
static std::map<std::tuple<std::vector<int>::const_iterator,
std::vector<int>::const_iterator>,
int> lookup_table;
std::map<std::tuple<std::vector<int>::const_iterator,
std::vector<int>::const_iterator>, int>::iterator lookup_it =
lookup_table.find(lookup_key);
if (lookup_it != lookup_table.end())
return lookup_it->second;
...
}
Довольно уродливый ИМО. Поэтому я добавлю несколько typedef в функцию, чтобы она выглядела лучше:
int sum(std::vector<int>::const_iterator first,
std::vector<int>::const_iterator last)
{
typedef std::tuple<std::vector<int>::const_iterator,
std::vector<int>::const_iterator> Lookup_key;
typedef std::map<Lookup_key, int> Lookup_table;
static Lookup_table lookup_table;
Lookup_table::iterator lookup_it = lookup_table.find(lookup_key);
if (lookup_it != lookup_table.end())
return lookup_it->second;
...
}
Код все еще немного неуклюж, но я избавляюсь от большинства кошмарных материалов. Но есть еще итераторы типа int, этот вариант избавляет от них:
typedef std::vector<int>::const_iterator Input_iterator;
int sum(Input_iterator first, Input_iterator last)
{
typedef std::tuple<Input_iterator, Input_iterator> Lookup_key;
typedef std::map<Lookup_key, int> Lookup_table;
static Lookup_table lookup_table;
Lookup_table::iterator lookup_it = lookup_table.find(lookup_key);
if (lookup_it != lookup_table.end())
return lookup_it->second;
...
}
Это выглядит чисто, но все еще читаемо?
Когда я должен использовать typedef? Как только у меня кошмарный тип? Как только это происходит не раз? Где я должен их положить? Должен ли я использовать их в сигнатурах функций или оставить их для реализации?
c++
coding-style
futlib
источник
источник
typedef Input_iterator std::vector<int>::const_iterator;
назад#define
не достаточно хорошо.Ответы:
Ваш последний пример очень удобен для чтения, но это зависит от того, где вы определяете typedef. Локальные определения типов (как в вашем втором примере) IMVHO почти всегда выигрывают.
Мне все еще нравится ваш третий пример, но вы можете подумать об именах и дать имена итераторам, которые сообщают о намерениях контейнера.
Другой вариант - сделать шаблон из вашей функции, чтобы он работал и с другими контейнерами. По линии
что также очень в духе STL.
источник
Думайте о
typedef
как об объявлении переменной, эквивалентном функции: она есть, чтобы вы ...Лично я остаюсь, если мне приходится читать длинные имена типа, как
std::vector<int>::const_iterator
неоднократно.Ваш третий пример не повторяется излишне и его легче всего читать.
источник
typedef
объявления служат по существу той же цели, что и инкапсуляция. По этой причине они почти всегда лучше всего помещаются в заголовочный файл, следуя тем же соглашениям об именах, что и ваши классы, потому что:typedef
, скорее всего, звонящие тоже будут, особенно как в вашем примере, где это используется в аргументах.Кроме того, ваш код напоминания будет намного чище, если вы абстрагируете его дальше, например:
источник