Когда я должен использовать typedef в C++?



в мои годы программирования на C++ (MFC) я никогда не чувствовал необходимости использовать typedef, Так что я действительно не знаю, для чего он используется. Где я должен его использовать? Существуют ли какие-либо реальные ситуации, когда использование typedef предпочтительнее? Или это действительно больше ключевое слово C-specific?

708   12  

12 ответов:

Метапрограммирование Шаблона

typedef и необходимые много метапрограммирование шаблона задачи -- всякий раз, когда класс рассматривается как "функция типа времени компиляции", a typedef используется как "значение типа времени компиляции" для получения результирующего типа. Например, рассмотрим простую метафункцию для преобразования типа указателя в его базовый тип:

template<typename T>
struct strip_pointer_from;

template<typename T>
struct strip_pointer_from<T*> {   // Partial specialisation for pointer types
    typedef T type;
};

пример: выражение типа strip_pointer_from<double*>::type оценивает в double. Обратите внимание, что шаблон метапрограммирование обычно не используется вне разработки библиотек.

Упрощение Типов Указателей Функций

typedef и полезны для предоставления короткого, резкого псевдонима сложным типам указателей функций:

typedef int (*my_callback_function_type)(int, double, std::string);

void RegisterCallback(my_callback_function_type fn) {
    ...
}

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

на машине, где sizeof (int) составляет 4 Вы можете

typedef int int32;

затем используйте int32 везде в коде. Когда вы переходите к реализации C++ , где sizeof (int) равно 2, то вы можете просто изменить typdef

typedef long int32;

и ваша программа все равно будет работать над новой реализацией.

использовать указатель на функцию

скрыть объявления указателя функции с помощью typedef

void (*p[10]) (void (*)() );

только немногие программисты могут сказать, что p-это "массив из 10 указателей на функцию, возвращающую void и принимающую указатель на другую функцию, которая возвращает void и не принимает аргументов."Громоздкий синтаксис почти неразборчив. Однако, вы можете значительно упростить его, используя объявления typedef. Во-первых, объявите typedef для " указатель на функцию, возвращающую void и не принимая никаких аргументов" следующим образом:

  typedef void (*pfv)();

затем объявите другой typedef для "указателя на функцию, возвращающую void и принимающую pfv" на основе typedef, который мы ранее объявили:

 typedef void (*pf_taking_pfv) (pfv);

теперь, когда мы создали pf_taking_pfv typedef как синоним громоздкого "указатель на функцию, возвращающую void и принимающую pfv", объявление массива из 10 таких указателей-это ветер:

  pf_taking_pfv p[10];

С

просто чтобы привести некоторые примеры для сказанного: контейнеры STL.

 typedef std::map<int,Froboz> tFrobozMap;
 tFrobozMap frobozzes; 
 ...
 for(tFrobozMap::iterator it=frobozzes.begin(); it!=map.end(); ++it)
 {
     ...
 }

это не редкость даже использовать typedefs как

typedef tFrobozMap::iterator tFrobozMapIter;
typedef tFrobozMap::const_iterator tFrobozMapCIter;

другой пример: использование общих указателей:

class Froboz;
typedef boost::shared_ptr<Froboz> FrobozPtr;

[обновление] согласно комментарию-куда их поставить?

последний пример - использование shared_ptr - легко: истинный материал заголовка-или, по крайней мере, прямой заголовок. Вам все равно нужно прямое объявление для shared_ptr, и одна из его заявленных преимуществ является то, что это безопасно для использования с Децл.

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

(да, xyzfwd.H-это боль. Я бы использовал их только в горячих точках - зная, что активных точек трудно определить. Виновата модель c++ compile+link...)

Container typedefs я обычно использую, где переменная контейнера объявлено-например, локально для локального var, как члены класса, когда фактический экземпляр контейнера является членом класса. Это хорошо работает, если фактический тип контейнера является детализацией реализации, не вызывая дополнительной зависимости.

если они станут частью особенности интерфейс, они объявляются вместе с интерфейсом, с которым они используются, например

// FrobozMangler.h
#include "Froboz.h"
typedef std::map<int, Froboz> tFrobozMap;
void Mangle(tFrobozMap const & frobozzes); 

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

  • объявить его вместе с содержимым типа (подходит для контейнеров, которые часто используются для этого типа)
  • переместить их в отдельный заголовок
  • перейдите к отдельному заголовку и сделайте его классом данных, где фактический контейнер снова является деталью реализации

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

typedef полезен во многих ситуациях.

в основном это позволяет создать псевдоним для типа. Когда / Если вам нужно изменить тип, остальная часть кода может быть неизменной (это зависит от кода, конечно). Например, предположим, что вы хотите iter на векторе c++

vector<int> v;

...

for(vector<int>::const_iterator i = v->begin(); i != v.end(); i++) {

// Stuff here

}

в будущем вы можете подумать, чтобы изменить вектор со списком, потому что тип операций, которые вы должны сделать на нем. Без typedef вы должны изменить все вхождения вектора в вашем коде. Но если вы пишете что-то вроде этого:

typedef vector<int> my_vect;

my_vect v;

...

for(my_vect::const_iterator i = v->begin(); i != v.end(); i++) {

// Stuff here

}

теперь вам просто нужно изменить одну строку кода (т. е. от "typedef vector<int> my_vect" на "typedef list<int> my_vect") и все работает.

оператор typedef также экономит ваше время, когда у вас есть сложные структуры данных, которые очень долго писать (и читать сложно)

одна хорошая причина использовать typedef, если тип чего-то может измениться. Например, предположим, что на данный момент 16-разрядные int подходят для индексирования некоторых наборов данных, потому что в обозримом будущем у вас будет менее 65535 элементов, и что ограничения пространства значительны или вам нужна хорошая производительность кэша. Однако в случае, если вам нужно использовать вашу программу в наборе данных с более чем 65535 элементами, вы хотите легко переключиться на более широкое целое число. Используйте typedef, и вы только должны изменить это в одном месте.

typedef позволяет не только иметь псевдоним для сложных типов, но и дает вам естественное место для документирования типа. Я иногда использую его в документальных целях.

бывают также случаи, когда я использую массив байтов. Теперь массив байтов может означать много вещей. typedef делает его удобный, чтобы определить мой байтовый массив в качестве "CRC32 сумма", или "fileContent", чтобы сделать мой код более читабельным.

реальное использование typedef:

  • предоставление дружественных псевдонимов для многословных шаблонных типов
  • предоставление дружественных псевдонимов для типов указателей функций
  • предоставление локальных меток для типов, например:

    template<class _T> class A
    {
        typedef _T T;
    };
    
    template<class _T> class B
    {
        void doStuff( _T::T _value );
    };
    

есть еще один вариант использования typedef, когда мы хотим включить вид независимый от контейнера код (но не точно!)

скажем у вас есть класс:

Class CustomerList{

public:
    //some function
private:
    typedef list<Customer> CustomerContainer;
    typedef CustomerContainer::iterator Cciterator;
};

приведенный выше код инкапсулирует внутреннюю реализацию контейнера с помощью typedef, и даже если в будущем контейнер списка должен быть изменен на vector или deque, пользователю класса CustomerList не нужно беспокоиться о точном контейнере реализация.

следовательно, typedef инкапсулирует и несколько помогает нам писать независимый от контейнера код

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

Я использую вид typedef в C# для дженериков / шаблонов. "NodeMapping "просто лучше читать/использовать и понимать тогда много"Dictionary". ПО МОЕМУ. Поэтому я бы рекомендовал его для шаблонов.

Typedef позволяет гибкость в вашем классе. Если вы хотите изменить тип данных в программе, вам не нужно менять несколько местоположений, а просто нужно изменить одно вхождение.

typedef <datatype example  int or double> value_type

вы можете дать nay имя вместо value_type, а value_type обычно это стандартное имя.

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

value_type i=0;     //same as a int or double i=0; 

... и Вам не нужен Typedef для перечисления или структуры.

или ты?

typedef enum { c1, c2 } tMyEnum;
typedef struct { int i; double d; } tMyStruct;

может быть лучше записать как

enum tMyEnum { c1, c2 }
struct  tMyStruct { int i; double d; };

это правильно? А как же с?

Comments

    Ничего не найдено.