Подтвердить что ты не робот

Когда следует использовать typedef в С++?

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

4b9b3361

Ответ 1

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

typedef необходим для многих шаблонов метапрограммирования задач - всякий раз, когда класс рассматривается как функция типа времени компиляции, 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) {
    ...
}

Ответ 2

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

На машине, где sizeof(int) равно 4, вы можете

typedef int int32;

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

typedef long int32;

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

Ответ 3

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

Скрыть объявления указателя функций С помощью 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];

из

Ответ 4

Просто для того, чтобы предоставить несколько примеров для вещей: STL-контейнеров.

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

Нестандартно даже использовать typedef, например

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

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

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

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

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

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

(Да, xyzfwd.h - это боль. Я бы использовал их только в горячих точках - зная, что горячие точки трудно идентифицировать. Позовите модель компиляции + С++...)

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

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

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

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

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

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

Ответ 5

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

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

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 также экономит ваше время, когда у вас сложные структуры данных, которые очень долго писать (и их трудно читать)

Ответ 6

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

Ответ 7

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

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

Ответ 8

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

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

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

Ответ 9

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

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

Class CustomerList{

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

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

Следовательно, typedef инкапсулирует и несколько помогает нам писать Container Independent code

Ответ 10

Всякий раз, когда он делает источник более понятным или лучше читать.

Я использую тип typedef в С# для generics/templates. "NodeMapping" просто лучше читать/использовать и понимать тогда много "Dictionary < string, XmlNode > ". ИМХО. Поэтому я рекомендую его для шаблонов.

Ответ 11

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; 

Ответ 12

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

Или вы?

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

лучше писать как

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

Это правильно? Как насчет C?