C ++ 11'de 'typedef' ve 'using' arasındaki fark nedir?


905

C ++ 11'de artık s usinggibi tür diğer adları yazmak için kullanabileceğimizi biliyorum typedef:

typedef int MyInt;

Anladığım kadarıyla:

using MyInt = int;

Ve bu yeni sözdizimi, " template typedef" ifadesini ifade etme yoluna sahip olma çabasından kaynaklandı :

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

Ancak, şablon olmayan ilk iki örnekte, standartta başka ince farklar var mı? Örneğin, typedeförtüşme "zayıf" bir şekilde yapılır. Yani yeni bir tür oluşturmaz, sadece yeni bir ad oluşturur (bu adlar arasında dönüşümler örtülüdür).

Aynı mı usingyoksa yeni bir tür mü oluşturuyor? Herhangi bir fark var mı?


215
Kişisel olarak yeni sözdizimini tercih ediyorum, çünkü düzenli değişken atamasına çok daha benziyor, okunabilirliği artırıyor. Örneğin, typedef void (&MyFunc)(int,int);ya da using MyFunc = void(int,int);mı tercih edersiniz ?
Matthieu M.

13
Tamamen katılıyorum, şimdi sadece yeni sözdizimini kullanıyorum. Bu yüzden gerçekten hiçbir fark olmadığından emin olmak istiyordum.
Klaim

80
@MatthieuM. bu ikisi farklı btw. Olmalı typedef void MyFunc(int,int);(ki aslında kötü görünmüyor) veyausing MyFunc = void(&)(int,int);
R. Martinho Fernandes

5
@ R.MartinhoFernandes Neden Gereklidir (&) içinde using MyFunc = void(&)(int,int);? MyFuncbir işleve başvuru anlamına mı geliyor? & 'ı atlarsanız ne olur ?
Zengin

7
Evet, bu bir işlev başvurusu. Eşdeğerdir typedef void (&MyFunc)(int,int);. Eğer atlarsanız &o eşdeğerdirtypedef void MyFunc(int,int);
R. Martinho Fernandes

Yanıtlar:


585

Standarttan (vurgu mayın) eşdeğerdirler (7.1.3.2):

Bir typedef-name, bir takma ad bildirimi ile de eklenebilir. Using anahtar sözcüğünü izleyen tanımlayıcı, typedef-name olur ve tanımlayıcıyı izleyen isteğe bağlı attribute-specifier-seq, bu typedef-name için geçerlidir. Typedef belirleyicisi tarafından tanıtılmış gibi aynı anlambilime sahiptir. Özellikle, yeni bir tür tanımlamaz ve tür kimliğinde görünmez.


24
Yanıttan itibaren, usinganahtar kelime bir üst küme gibi görünüyor typedef. Peki, typdefgelecekte kullanımdan kaldırılacak mı?
iammilind

49
Kullanımdan kaldırma, mutlaka kaldırılma niyetini göstermez - Başka bir yöntemi tercih etmek için çok güçlü bir öneri olarak durur.
Iron Savior

18
Ama sonra neden typedef'in şablonlanmasına izin vermediklerini merak ediyorum. Anlambilimi şablonlarla iyi çalışmadığından usingsöz dizimini tam olarak tanıttıklarını bir yerde okuduğumu hatırlıyorum typedef. Hangi bir şekilde usingtamamen aynı semantiğe sahip olduğu tanımlanan ile çelişiyor .
celtschk

12
@celtschk: Teklifin nedeni hakkında konuşuldu n1489. Şablon takma değil bir türü için bir takma ama şablonların bir grup için bir takma ad. typedefYeni bir sözdizimine ihtiyaç duyulduğunu hissetmek arasında bir ayrım yapmak . Ayrıca, OP'nin sorusunun şablon olmayan sürümler arasındaki farkla ilgili olduğunu unutmayın.
Jesse Good

4
Peki bu fazlalık neden ortaya çıktı? Aynı amaç için 2 sözdizimi. Ve hiçbir typdefzaman itiraz edilmediğini görmüyorum .
Benoît

237

Bunlar dışında büyük ölçüde aynılar:

Diğer ad bildirimi şablonlarla uyumluyken, C stili typedef uyumlu değildir.


29
Özellikle cevabın basitliğine düşkün ve yazı dizisinin kökenine dikkat çekiyor.
g24l

1
@ g24l demek typedef ... muhtemelen
Marc.2377

typedefEğer sorabilirsem C ve C ++ arasındaki fark nedir ?
McSinyx

196

Kullanarak şablonlar içinde kullanıldıklarında sözdizimi bir avantaja sahiptir. Tür soyutlamaya ihtiyacınız varsa, ancak gelecekte belirtilebilmesi için şablon parametresini de tutmanız gerekir. Böyle bir şey yazmalısın.

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; }

Ama kullanarak sözdizimi bu kullanım durumunu kolaylaştırır.

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

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

35
Yine de bu soruya işaret ettim. Sorum şablon kullanmıyorsanız typedef ile herhangi bir fark var. Örneğin, 'Foo foo {init_value};' 'Foo foo (init_value)' yerine her ikisinin de aynı şeyi yapması gerekir, ancak tam olarak aynı kuralları izlememelidir. Bu yüzden / typedef kullanarak benzer bir gizli fark olup olmadığını merak ediyordum.
Klaim

24

Bunlar aslında aynı ama usingsağlayan alias templatesoldukça kullanışlıdır. Bulabildiğim iyi bir örnek şöyledir:

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

Yani, std::add_const_t<T>yerine kullanabiliriztypename std::add_const<T>::type


Bildiğim kadarıyla, std ad
boşluğuna bir

5
@someonewithpc Hiçbir şey eklemiyordum, zaten var, sadece typename kullanımının bir örneğini gösteriyordum. Lütfen en.cppreference.com/w/cpp/types/add_cv adresini ziyaret
Validus Oculus

9

Ben orijinal afişi büyük cevabı vardır biliyorum, ama gelen önemli bir not var var gibi bu iş parçacığı üzerinde tökezleyerek herkes için teklifte Bence özellikle hakkında da açıklamalarda bulunan endişeler, burada tartışmaya değerli bir şey ekler typedefanahtar kelimedir gelecekte kullanımdan kaldırılmış olarak işaretlenecek veya gereksiz / eski olduğu için kaldırılacak:

Şablon takma adlarını tanıtmak için typedef ... anahtar kelimesinin (yeniden) kullanılması önerilmiştir:

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

Bu gösterim, bir tür takma adı tanıttığı bilinen bir anahtar kelimeyi kullanma avantajına sahiptir. Bununla birlikte, aralarında takma adın bir tür değil, bir şablon belirtmediği bir bağlamda bir tür adı için bir takma ad tanıttığı bilinen bir anahtar sözcüğü kullanma karmaşasını da görüntüler; Vecolduğu değil bir türü için bir takma ve typedef-ad için alınmamalıdır. Ad Vec, ailenin bir adıdır std::vector<•, MyAllocator<•> >- burada madde işaretinin bir tür adı için yer tutucusu olduğu için “typedef” sözdizimini önermiyoruz.Öte yandan cümle

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

şu şekilde okunabilir / yorumlanabilir: şu andan itibaren, Vec<T>eşanlamlı olarak kullanacağımstd::vector<T, MyAllocator<T> > . Bu okuma ile, takma ad için yeni sözdizimi oldukça mantıklı görünüyor.

Bana göre, bu typedef, C ++ içindeki anahtar kelime için sürekli destek anlamına gelir, çünkü yine de kodu daha okunabilir ve anlaşılır hale getirebilir .

usingAnahtar kelimeyi güncellemek özellikle şablonlar içindi ve şablonlar dışında çalışırken usingve typedefmekanik olarak özdeş olduğunuzda (kabul edilen cevapta belirtildiği gibi) , bu nedenle seçim, okunabilirlik ve niyet iletişimi nedeniyle tamamen programcıya kalmış .


2

Her iki anahtar kelime de eşdeğerdir, ancak birkaç uyarı vardır. Bunlardan biri, bir işlev işaretçisi ile bildirmenin, ile using T = int (*)(int, int);olduğundan daha net olmasıdır typedef int (*T)(int, int);. İkincisi, şablon takma ad formu ile mümkün değildir typedef. Üçüncüsü, typedefgenel API başlıklarında C API'sinin gösterilmesinin gerekmesidir .


0

Typedef bildirimleri, diğer ad bildirimleri başlangıç ​​deyimleri olarak kullanılamaz

Ancak, şablon olmayan ilk iki örnekte, standartta başka ince farklar var mı?

Bir köşe durumu da olsa, typedef bildirimi bir init deyimidir ve bu nedenle başlatma deyimlerine izin veren bağlamlarda kullanılabilir

// C++11 (C++03) (init. statement in for loop iteration statements).
for(typedef int Foo; Foo{} != 0;) {}

// C++17 (if and switch initialization statements).
if (typedef int Foo; true) { (void)Foo{}; }
//  ^^^^^^^^^^^^^^^ init-statement

switch(typedef int Foo; 0) { case 0: (void)Foo{}; }
//     ^^^^^^^^^^^^^^^ init-statement

// C++20 (range-based for loop initialization statements).
std::vector<int> v{1, 2, 3};
for(typedef int Foo; Foo f : v) { (void)f; }
//  ^^^^^^^^^^^^^^^ init-statement

Bir ise takma-bildirimi olan olmayan bir başlatma-ifadesi ve bu yüzden olmayabilir bağlamlarda kullanılabilir başlatma ifadeleri izin veren

// C++ 11.
for(using Foo = int; Foo{} != 0;) {}
//  ^^^^^^^^^^^^^^^ error: expected expression

// C++17 (initialization expressions in switch and if statements).
if (using Foo = int; true) { (void)Foo{}; }
//  ^^^^^^^^^^^^^^^ error: expected expression

switch(using Foo = int; 0) { case 0: (void)Foo{}; }
//     ^^^^^^^^^^^^^^^ error: expected expression

// C++20 (range-based for loop initialization statements).
std::vector<int> v{1, 2, 3};
for(using Foo = int; Foo f : v) { (void)f; }
//  ^^^^^^^^^^^^^^^ error: expected expression
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.