Яка різниця між "typedef" і "use" в C ++ 11?


905

Я знаю, що в C ++ 11 тепер ми можемо використовувати usingдля написання псевдонімів типу, наприклад typedefs:

typedef int MyInt;

З того, що я розумію, рівнозначне:

using MyInt = int;

І цей новий синтаксис з'явився із спроби створити спосіб " template typedef":

template< class T > using MyType = AnotherType< T, MyAllocatorType >;

Але, маючи перші два приклади, що не є шаблонами, чи є якісь інші тонкі відмінності в стандарті? Наприклад, typedefs роблять псевдонім «слабким» способом. Тобто це не створює нового типу, а лише нове ім’я (перетворення між тими іменами неявні).

Це те саме usingчи він генерує новий тип? Чи є відмінності?


215
Я особисто віддаю перевагу новому синтаксису, оскільки він набагато більше схожий на регулярне призначення змінних, покращуючи читабельність. Наприклад, ви віддаєте перевагу typedef void (&MyFunc)(int,int);чи using MyFunc = void(int,int);?
Матьє М.

13
Я повністю згоден, я зараз використовую новий синтаксис. Ось чому я питав, щоб бути впевненим, що насправді різниці немає.
Клайм

80
@MatthieuM. ці два різні btw. Це повинно бути typedef void MyFunc(int,int);(що насправді не виглядає так погано), абоusing MyFunc = void(&)(int,int);
Р. Мартіньо Фернандес

5
@ R.MartinhoFernandes, навіщо вам потрібно (&) у using MyFunc = void(&)(int,int);? чи означає MyFuncце посилання на функцію? що робити, якщо пропустити & ?
Багатий

7
Так, це посилання на функцію. Це рівнозначно typedef void (&MyFunc)(int,int);. Якщо опустити &його, це рівнозначноtypedef void MyFunc(int,int);
Р. Мартіньо Фернандес

Відповіді:


584

Вони еквівалентні у порівнянні зі стандартом (міна наголосу) (7.1.3.2):

Ім'я typedef також може бути введено декларацією псевдоніму. Ідентифікатор, що використовується за ключовим словом, що використовується, стає іменем typedef, а необов'язковий атрибут-специфікатор-seq, що слідує за ідентифікатором, що відноситься до цього імені typedef. Він має таку саму семантику, як якщо б вона була введена специфікатором typedef. Зокрема, він не визначає новий тип і не повинен відображатися в ідентифікаторі типу.


24
З відповіді, usingключове слово, здається, є сукупністю typedef. Тоді чи typdefбуде в майбутньому застарілим?
iammilind

49
Депресія не обов'язково вказує на намір видалити - це просто є дуже наполегливою рекомендацією віддати перевагу іншим засобам.
Залізний Спас

18
Але тоді мені цікаво, чому вони не дозволили шаблону typedef шаблонувати. Я пам’ятаю, що десь читав, що вони ввели usingсинтаксис саме тому, що typedefсемантика не працювала добре із шаблонами. Що якимось чином суперечить тому, що usingвизначено, що має абсолютно однакову семантику.
celtschk

12
@celtschk: Про причину йдеться у пропозиції n1489. Псевдонім шаблону - це не псевдонім для типу, а псевдонім для групи шаблонів. Для розмежування typedefвідчутого необхідність у новому синтаксисі. Також пам’ятайте, що питання ОП полягає в різниці між нешаблонними версіями.
Джессі Добрий

4
То чому ж ця надмірність введена? 2 синтаксиси з тією ж метою. І я ніколи не бачу, щоб typdefбути застарілим ніколи.
Беноо

237

Вони багато в чому однакові, за винятком того, що:

Декларація псевдоніму сумісна з шаблонами, тоді як тип стилю C не використовується.


29
Особливо любить простоту відповіді та вказує на походження набору тексту.
g24l

1
@ g24l ви маєте на увазі typedef ... певно
Marc.2377

У чому різниця між C і C ++, typedefякщо я можу запитати?
McSinyx

196

З використанням синтаксису має перевагу при використанні в шаблонах. Якщо вам потрібна абстракція типу, але також потрібно зберегти параметр шаблону, щоб можна було вказати в майбутньому. Вам слід написати щось подібне.

template <typename T> struct whatever {};

template <typename T> struct rebind
{
  typedef whatever<T> type; // to make it possible to substitue the whatever in future.
};

rebind<int>::type variable;

template <typename U> struct bar { typename rebind<U>::type _var_member; }

Але використання синтаксису спрощує цей випадок використання.

template <typename T> using my_type = whatever<T>;

my_type<int> variable;
template <typename U> struct baz { my_type<U> _var_member; }

35
Я вже вказував на це питання. Моє питання про те, якщо ви не використовуєте шаблон, чи є різниця з typedef. Як, наприклад, коли ви використовуєте "Foo foo {init_value};" замість "Foo foo (init_value)" обидва повинні робити те саме, але не фольгувати абсолютно однаковими правилами. Тож мені було цікаво, чи є схожа прихована різниця з використанням / typedef.
Клаїм

24

Вони по суті однакові, але usingнадають, alias templatesщо є досить корисним. Хороший приклад, який я міг би знайти:

namespace std {
 template<typename T> using add_const_t = typename add_const<T>::type;
}

Отже, ми можемо використовувати std::add_const_t<T>замість цьогоtypename std::add_const<T>::type


Наскільки я знаю, це не визначена поведінка додавати що-небудь всередині простору імен std
whowithpc

5
@someonewithpc Я нічого не додавав, він уже існує, я просто показував приклад використання назви типу. Перевірте en.cppreference.com/w/cpp/types/add_cv
Validus Oculus

9

Я знаю, що оригінальний плакат має чудову відповідь, але для тих, хто натикається на цю тему, як у мене, є важлива примітка з пропозиції, яка, на мою думку, додає щось важливе для обговорення тут, особливо для занепокоєння в коментарях щодо того, чиtypedef ключове слово буде позначено як застаріле в майбутньому, або видалено за надмірність / старість:

Запропоновано (повторно) використовувати ключове слово typedef ... для введення псевдонімів шаблонів:

template<class T>
  typedef std::vector<T, MyAllocator<T> > Vec;

Ця позначення має перевагу у використанні вже відомого ключового слова для введення псевдоніма типу. Однак він також відображає кілька недоліків [sic], серед яких плутанина використання ключового слова, відомого для введення псевдоніма для імені типу в контексті, де псевдонім не позначає тип, а шаблон; Vecце НЕ псевдонім типу, і не повинні бути прийняті для імені-ЬурейеЕ. Ім'я Vec- це ім'я для родини std::vector<•, MyAllocator<•> >- там, де куля є заповнювачем для імені типу. Отже, ми не пропонуємо синтаксис "typedef". З іншого боку, речення

template<class T>
  using Vec = std::vector<T, MyAllocator<T> >;

можна читати / інтерпретувати як: з цього моменту я буду використовувати Vec<T>як синонімstd::vector<T, MyAllocator<T> > . При такому читанні новий синтаксис для згладжування здається досить логічним.

Для мене це означає постійну підтримку typedefключового слова в C ++, оскільки воно все ще може зробити код більш зрозумілим і зрозумілим .

Оновлення usingключового слова було спеціально для шаблонів, і (як було зазначено у прийнятій відповіді), коли ви працюєте з не-шаблонами usingі typedefмеханічно ідентичні, тому вибір повністю залежить від програміста на основі читабельності та зв'язку намірів .


2

Обидва ключові слова рівноцінні, але є кілька застережень. Одне полягає в тому, що оголошення функції покажчика функції using T = int (*)(int, int);чіткіше, ніж з typedef int (*T)(int, int);. Друге - це те, що форма псевдоніма шаблону неможлива typedef. По-третє, розкриття API API вимагатиме typedefу загальнодоступних заголовках.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.