#cpp #cpp11
Какие есть отличия using от typedef кроме того, что using работает с шаблонами? Если только в этом, то почему нельзя было добавить эту поддержку в typedef?
Ответы
Ответ 1
Директива using существует только в С++, typedef - это наследство от чистого C, в нём нет шаблонов. Тем более что они отличаются по своей сути. При использовании typedef мы создаём синоним имени типа, а using позволяет создать синоним типа, либо включить в текущее пространство имён существующее.Ответ 2
using позволяет писать более красивый код и позволяет избавиться от наследия typedef, который имеет в своём имени def, который может подразумевать definition, которого на самом деле не происходит. using это замена typedef с некоторыми добавками, каких typedef не имеет. В современном коде использовать typedef нет никакого смысла. Более подробно о том, что думают об этом те, кто предложили это изменение в стандарт, а также об истории using можно почитать на английской части SO.Ответ 3
Я бы сказал так - главное преимущество using перед typedef - при работе с шаблонами. шаблоны. В частности, объявления псевдонимов могут быть шаблонизированы (и в этом случае они называются шаблонами псевдонимов), в то время как typedef — нет. Это дает программистам на C++11 простой механизм для выражения того, что в C++98 можно было выразить только хакерскими способами, с помощью typedef, вложенных в шаблонные struct. Рассмотрим, например, определение синонима для связанного списка, который использует пользовательский распределитель памяти MyAlloc. В случае шаблонов псевдонимов это просто: // MyAllocListявляется синонимом для std::list >: template using MyAllocList = std::list >; MyAllocList lw; // Клиентский код В случае typedef приходится идти длинным окружным путем: // MyAllocList ::type — синоним для std::list >: template struct MyAllocList { typedef std::list > type; }; MyAllocList ::type lw; // Клиентский код Все еще хуже. Если вы хотите использовать typedef в шаблоне для создания связанного списка, хранящего объекты типа, указанного параметром шаблона, имя, указанное в typedef, следует предварять ключевым словом typename: template class Widget { // Widget содержит private: // MyAllocList , typename MyAllocList ::type list; // как член-данные … }; Здесь MyAllocList ::type ссылается на тип, который зависит от параметра типа шаблона (T). Тем самым MyAllocList ::type является зависимым типом, а одно из правил C++ требует, чтобы имена зависимых типов предварялись ключевым словом typename. Если MyAllocList определен как шаблон псевдонима, это требование использования ключевого слова typename убирается (как и громоздкий суффикс “::type”): template using MyAllocList = std::list >; // Как и ранее template class Widget { private: MyAllocList list; // Ни typename, … // ни ::type }; Для вас MyAllocList (т.е. использование шаблона псевдонима) может выглядеть как зависимый от параметра шаблона T, как и MyAllocList ::type (т.е. как и использование вложенного typedef), но вы не компилятор. Когда компилятор обрабатывает шаблон Widget и встречает использование MyAllocList (т.е. использование шаблона псевдонима), он знает, что MyAllocList является именем типа, поскольку MyAllocList является шаблоном псевдонима: он обязан быть именем типа. Тем самым MyAllocList оказывается независимым типом, и спецификатор typename не является ни требуемым, ни разрешенным. С другой стороны, когда компилятор видит MyAllocList ::type (т.е. использование вложенных typedef) в шаблоне Widget, он не может знать наверняка, что эта конструкция именует тип, поскольку это может быть специализация MyAllocList, с которой он еще не встречался и в которой MyAllocList ::type ссылается на нечто, отличное от типа. Это звучит глупо, но не вините компиляторы за то, что они рассматривают такую возможность. В конце концов, это люди пишут такой код. Например, некая заблудшая душа вполне в состоянии написать следующее: class Wine { … }; template<> // Специализация MyAllocList в class MyAllocList { // которой T представляет собой Wine private: enum class WineType // См. в разделе 3.4 информацию об { White, Red, Rose }; // "enum class" WineType type; // В этом классе type представляет … // собой данные-член! }; Как видите, MyAllocList ::type не является типом. Если Widget инстанцирован с Wine, MyAllocList ::type в шаблоне Widget представляет собой данные-член, а не тип. Ссылается ли MyAllocList ::type на тип в шаблоне Widget, зависит от того, чем является T, а потому компиляторы требуют, чтобы вы точно указывали, что это тип, предваряя его ключевым словом typename. Ответ 4
Еще одно удобство using по сравнению с typedef можно увидеть на примере указателя на функцию (аргумент int, возвращает float): typedef float (*func_ptr)(int); using func_ptr = float (*)(int); Это дело вкуса, но мне по душе больше второй вариант. Вычитано у Скотта Майерса
Комментариев нет:
Отправить комментарий