Std :: initializer_list neden yerleşik bir dil değil?


97

Neden std::initializer_listbir çekirdek dil yerleşik değil ?

Bana öyle geliyor ki, C ++ 11'in oldukça önemli bir özelliği ve yine de kendi ayrılmış anahtar kelimesine (veya benzer bir şeye) sahip değil.

Bunun yerine, initializer_listbu kadar sadece özel, örtülü sahiptir standart kütüphaneden bir şablon sınıfı eşlemesi yeni gelen hazırladı-init-liste {...} derleyici tarafından işlenir oldu sözdizimi.

İlk bakışta bu çözüm oldukça zordur .

C ++ diline yapılan yeni eklemelerin artık uygulanacağı yol bu mu: Çekirdek dil tarafından değil, bazı şablon sınıflarının örtük rolleriyle mi?


Lütfen şu örnekleri göz önünde bulundurun:

   widget<int> w = {1,2,3}; //this is how we want to use a class

neden yeni bir sınıf seçildi:

   widget( std::initializer_list<T> init )

bu fikirlerden herhangi birine benzer bir şey kullanmak yerine :

   widget( T[] init, int length )  // (1)
   widget( T... init )             // (2)
   widget( std::vector<T> init )   // (3)
  1. klasik bir dizi, muhtemelen şuraya constburaya ekleyebilirsiniz
  2. dilde zaten üç nokta var (var-args, şimdi çeşitli şablonlar), neden sözdizimini yeniden kullanmıyorsunuz (ve yerleşik hissettirin )
  3. yalnızca mevcut bir kapsayıcı ekleyebilir constve&

Hepsi zaten dilin bir parçası. Sadece ilk 3 fikrimi yazdım, başka birçok yaklaşımın olduğuna eminim .


26
Standartlar komitesi yeni anahtar kelimeler eklemekten nefret ediyor !
Alex Chamberlain

11
Bunu anlıyorum, ancak dili genişletmenin pek çok yolu var ( anahtar kelime sadece bir örnekti )
emesx

10
std::array<T>'dilin bir parçası' değil std::initializer_list<T>. Ve bunlar, dilin dayandığı neredeyse tek kütüphane bileşenleri değildir. Bkz. new/ delete,, type_infoÇeşitli istisna türleri size_t, vb.
bames53

6
@Elmes: Bunu önerirdim const T(*)[N], çünkü bu nasıl std::initializer_listçalıştığına çok benziyor .
Mooing Duck

1
Bu, neden std::arrayveya statik boyutlu bir dizinin neden daha az arzu edilen alternatifler olduğunu yanıtlar .
boycy

Yanıtlar:


48

stdAd alanında tanımlanan türleri döndüren "çekirdek" dil özelliklerinin örnekleri zaten vardı . typeiddöner std::type_infove (belki bir noktayı esnetme) sizeofdöndürür std::size_t.

İlk durumda, bu sözde "çekirdek dil" özelliğini kullanmak için zaten standart bir başlık eklemeniz gerekir.

Şimdi, başlatıcı listeleri için, nesneyi oluşturmak için herhangi bir anahtar sözcüğe gerek olmadığı görülür, sözdizimi içeriğe duyarlı küme ayraçlarıdır. Bunun dışında aynı şey type_info. Kişisel olarak, bir anahtar kelimenin yokluğunun onu "daha karmaşık" hale getirdiğini düşünmüyorum. Belki biraz daha şaşırtıcı, ancak amacın kümeler için zaten izin verilen aynı çaprazlı başlatıcı sözdizimine izin vermek olduğunu unutmayın.

Yani evet, gelecekte bu tasarım ilkesinden daha fazlasını bekleyebilirsiniz:

  • Yeni anahtar kelimeler olmadan yeni özellikleri tanıtmanın mümkün olduğu daha fazla durum ortaya çıkarsa, komite bunları alacaktır.
  • yeni özellikler karmaşık türler gerektiriyorsa, bu türler stdyerleşik yerine yerleştirilecektir .

Dolayısıyla:

  • yeni bir özellik karmaşık bir tür gerektiriyorsa ve yeni anahtar sözcükler olmadan tanıtılabiliyorsa, burada sahip olduğunuz şeyi elde edersiniz, bu yeni anahtar sözcükler içermeyen ve kitaplık türlerini kullanan "temel dil" sözdizimidir std.

Bence, "çekirdek dil" ile standart kitaplıklar arasında C ++ 'da mutlak bir ayrım olmadığıdır. Standartta farklı bölümler var ama her biri diğerine atıfta bulunuyor ve her zaman böyle oldu.

C ++ 11'de başka bir yaklaşım daha vardır, bu da lambdaların derleyici tarafından oluşturulan anonim türlere sahip nesneleri tanıtmasıdır . İsimleri olmadığı için bir isim alanında değiller, kesinlikle içinde değiller std. Bu, başlatıcı listeleri için uygun bir yaklaşım değildir, çünkü birini kabul eden kurucuyu yazarken tür adını kullanırsınız.


1
Bana öyle geliyor ki , türlerin bu tür üstü kapalı rolleri nedeniyle bu ayrım mümkün değil (mailny?) . type_infove size_tgüzel argümanlar .. peki size_tsadece bir typedef .. öyleyse bunu atlayalım. Arasındaki fark type_infove initializer_listilk olarak bir sonucu olduğunu açıkça operatör ve bir ikinci kapalı derleyici harekete. Ayrıca bu, bana öyle geliyor initializer_list olabilir ama daha iyi bazıları zaten var olan konteynerler ile değiştirilir .. veya: herhangi bir kullanıcı argüman türü olarak beyan!
emesx

4
... ya da için bir kurucu yazdım eğer basit bir nedeni olabilir vectoro alan bir arraysonra gelen bir vektör yapılandırmak olabilir herhangi sadece bir başlatıcı listesi sözdizimi tarafından oluşturulmaz sağ tip dizisi. Herhangi birinden kapsayıcılar inşa arrayetmenin kötü bir şey olacağından emin değilim , ancak yeni sözdizimini tanıtmak komitenin amacı değil.
Steve Jessop

2
@Christian: Hayır, kurucuları std::arraybile yok. Durum std::arraybasitçe toplu başlatma. Ayrıca, bu tartışma biraz uzadığı için, sizi Lounge <C ++> sohbet odasında bana katılmaya davet ediyorum.
Xeo

3
@ChristianRau: Xeo, başlatıcı listesi oluşturulduğunda öğelerin kopyalandığı anlamına gelir. Bir başlatıcı listesinin kopyalanması, içerilen öğeleri kopyalamaz.
Mooing Duck

2
@Christian List-initialisation, initializer_list anlamına gelmez. İyi ole doğrudan başlatma veya toplu başlatma dahil olmak üzere birçok şey olabilir. Bunların hiçbiri initializer_list dahil (ve bazıları sadece olamaz bu şekilde çalışmaz).
R. Martinho Fernandes

42

C ++ Standart Komitesi, muhtemelen mevcut kodu kırma riskini artırdığı için yeni anahtar kelimeler eklememeyi tercih ediyor gibi görünüyor (eski kod, bu anahtar kelimeyi bir değişkenin adı, bir sınıf veya başka bir şey olarak kullanabilir).

Dahası, bana göre std::initializer_listşablonlu kapsayıcı olarak tanımlamanın oldukça zarif bir seçim olduğunu düşünüyorum: eğer bir anahtar kelime olsaydı, onun temelindeki türe nasıl erişirdiniz? Bunu nasıl yinelersiniz? Bir sürü yeni operatöre de ihtiyacınız olacak ve bu sizi standart kapsayıcılarla yapabileceğiniz aynı şeyleri yapmak için daha fazla ad ve daha fazla anahtar kelime hatırlamaya zorlar.

Bir std::initializer_listkapsayıcı gibi davranmak , size bunlardan herhangi biriyle çalışan genel kod yazma fırsatı verir.

GÜNCELLEME:

Öyleyse neden var olanların bir kombinasyonunu kullanmak yerine yeni bir tür kullanılsın? (yorumlardan)

Başlangıç ​​olarak, diğer tüm kapsayıcılar, derleyici tarafından oluşturulan bir koleksiyon için arzu edilmeyen öğeleri eklemek, kaldırmak ve yerleştirmek için yöntemlere sahiptir. Tek istisna, std::array<>sabit boyutlu bir C-stili diziyi saran ve bu nedenle tek makul aday olarak kalmasıdır.

Ancak, Nicol bolas doğru açıklamalarda işaret arasında bir temel fark, std::initializer_listve (dahil diğer tüm standart konteyner std::array<>) ikinci olanlar olması değeri anlambilim ise, std::initializer_listvar referans semantik . Bir kopyalama std::initializer_listÖrneğin, içerdiği unsurların bir kopyasını neden olmaz.

Ayrıca (bir kez daha Nicol Bolas'ın izniyle), destek başlatma listeleri için özel bir konteynere sahip olmak, kullanıcının başlatma gerçekleştirme yolunda aşırı yüklemeye izin verir.


4
Öyleyse neden var olanların bir kombinasyonunu kullanmak yerine yeni bir tür kullanılsın?
emesx

3
@elmes: Aslında daha çok benziyor std::array. Ancak bir derleme zamanı dizisini sararken std::arraybelleği ayırır std::initializaer_list. Bunu char s[] = "array";ve arasındaki fark olarak düşünün char *s = "initializer_list";.
rodrigo

2
Ve bunun normal bir tip olması, aşırı yükleme, şablon uzmanlığı, isim süsleme ve benzerlerini sorun yaratmaz.
rodrigo

2
@rodrigo: std::arrayherhangi bir bellek ayırmaz, bu basit T arr[N];, arka planda olanla aynı şeydir std::initializer_list.
Xeo

6
@Xeo: T arr[N] tahsis yapar belki değil dinamik yığın ama başka bir yerde, hafızayı ... Yani yapar std::array. Bununla birlikte, boş olmayan bir initializer_listkullanıcı tarafından oluşturulamaz, bu nedenle açık bir şekilde bellek ayıramaz.
rodrigo

6

Bu yeni bir şey değil. Örneğin, for (i : some_container)güvenir belirli yöntemlerle veya bağımsız fonksiyonlarının varlığı halinde some_containersınıfında. Hatta C #, .NET kitaplıklarına daha fazla güveniyor. Aslında bunun oldukça zarif bir çözüm olduğunu düşünüyorum çünkü dil özelliklerini karmaşıklaştırmadan sınıflarınızı bazı dil yapılarına uyumlu hale getirebilirsiniz.


2
sınıfta veya tek başına yöntemler beginve endyöntemler. Bu biraz farklı bir IMO.
emesx

3
Bu mu? Yine kodunuzun belirli yapısına dayanan saf bir dil yapınız var. Örneğin, yeni bir anahtar kelime iterable class MyClass { };
ekleyerek

ama yöntemleri istediğiniz yere yerleştirebilirsiniz, istediğiniz gibi uygulayabilirsiniz .. Bazı benzerlikler var, katılıyorum! Bu soru initializer_listbununla ilgili
emesx

4

Bu gerçekten yeni bir şey değil ve kaç kişinin belirttiği bu uygulama C ++ 'da ve orada, mesela C #' da var.

Andrei Alexandrescu bununla ilgili güzel bir noktadan bahsetti: Bunu hayali "çekirdek" ad alanının bir parçası olarak düşünebilirsiniz, o zaman daha mantıklı olacaktır.

: Yani, aslında böyle bir şey var core::initializer_list, core::size_t, core::begin(), core::end()ve bu kadar. Bu, stdad alanının içinde bazı temel dil yapılarının bulunması talihsiz bir tesadüftür .


2

Sadece standart kitaplıkta tamamen çalışmakla kalmaz. Standart kitaplığa dahil olmak, derleyicinin akıllıca hileler oynayamayacağı anlamına gelmez.

Her durumda mümkün olmasa da, şunu söyleyebilir: bu tür iyi bilinir veya basit bir türdür, hadi göz ardı edelim initializer_listve başlatılan değerin ne olması gerektiğine dair bir hafıza görüntüsüne sahip olalım.

Diğer bir deyişle, int i {5};eşit olabilir int i(5);veya int i=5;hatta intwrapper iw {5};nerede intwrapperönemsiz bir yapıcı, bir alarak bir int fazla sınıf sarma basit birinitializer_list


Gerçekte bunun gibi "zekice oyunlar" oynayan tekrarlanabilir derleyici örneklerimiz var mı? Bu tür altında nedenine duruyor olarak eğer ama ispat görmek istiyorum.
underscore_d

Derleyicileri optimize etme fikri, derleyicinin kodu herhangi bir eşdeğer koda dönüştürebilmesidir. Özellikle C ++, "ücretsiz" soyutlamalar için optimizasyona dayanır. Standart kitaplıktaki kodu değiştirme fikri yaygındır (gcc yerleşik listesine bakın gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html ).
Paul de Vrieze

Aslında, int i {5}herhangi bir şeyi içeren fikriniz std::initializer_listyanlıştır. intyapıcı alımı yoktur std::initializer_list, bu nedenle 5doğrudan onu inşa etmek için kullanılır. Yani ana örnek konu dışıdır; yapılacak hiçbir optimizasyon yoktur. Bunun ötesinde std::initializer_list, derleyicinin 'hayali' bir dizi yaratmasını ve vekaletini almasını içerdiğinden, optimizasyonu destekleyebilir, ancak bu derleyicideki 'sihirli' kısımdır, dolayısıyla genel olarak iyileştiricinin güzel ile akıllıca bir şey yapıp yapamayacağından ayrıdır. 2 yineleyici içeren donuk nesne
alt

1

Çekirdek dilin bir parçası değildir çünkü tamamen kitaplıkta uygulanabilir, sadece line operator newve operator delete. Derleyicileri daha karmaşık hale getirmenin avantajı ne olabilir?

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.