Şablonları ve isim aramayı anlamaya çalışmak


9

Aşağıdaki kod parçacıklarını anlamaya çalışıyorum

Snippet # 1

template <typename T>
struct A
{
    static constexpr int VB = T::VD;
};

struct B : A<B>
{
};

Ne gcc9 ne de clang9 buraya bir hata atmıyor.

S. Bu kod neden derleniyor? A<B>B'den miras alırken somutlaşmıyor muyuz ? B'de VD yoktur, bu yüzden derleyici buraya bir hata atmamalı mı?

Snippet # 2

template <typename T>
struct A
{
    static constexpr auto AB = T::AD; // <- No member named AD in B
};

struct B : A<B>
{
    static constexpr auto AD = 0xD;
};

Bu durumda, gcc9 iyi derler, ancak clang9 "B'de AD adında üye yok" hatası verir.

S. Neden gcc9 ile derleniyor / neden clang9 ile derlenmiyor?

Snippet # 3

template <typename T>
struct A
{
    using TB = typename T::TD;
};

struct B : A<B>
{
    using TD = int;
};

Burada hem clang9 hem de gcc9 hata veriyor. gcc9, "tamamlanmamış B" türünün geçersiz kullanımı "diyor.

S. B yapısı burada eksikse neden # 2 snippet'inde eksik değil?

Derleyici bayrakları kullandı: -std=c++17 -O3 -Wall -Werror. Şimdiden teşekkürler!!!


@xception ile struct Börneklenmiyor mu? AB
Değişken Yan Etki

clang9 "B'de AD adında üye yok" hatası veriyor . Beksik olduğu gibi ... Ancak üye ne zaman somutlaştırılacağından emin
değilim

@MutableSideEffect oh evet, benim hatam, bunu bir şablon olarak da oku :(
xception

@ Jarod42 Peki neden gcc derleme iyi?
Değişken Yan Etki

1
Bu soruyu "daha fazla odaklanmaya ihtiyaç" olarak işaretledim ve soru gerçekten birden fazla soru içeriyor (dolayısıyla sonucum), peki neden bayrağım yanlış?
Dominique

Yanıtlar:


4

Bunların esasen [temp.inst] / 2'ye (vurgu mayın) kadar kaybolacağına inanıyorum :

Bir sınıf şablonu uzmanlık örtülü instantiation değil tanımların, bildirimleri örtülü örnekleme neden , varsayılan argümanlar veya noexcept-belirteçleri arasında sınıf üye fonksiyonları, üye sınıflar, kapsamlı üye numaralandırmalar, statik veri üyeleri , üye şablonu, ve Arkadaşlar; [...]

ve [sıcaklık] / 9

Bir uygulama, böyle bir örnekleme gerekmedikçe, sınıf şablonunun statik veri üyesini […] dolaylı olarak başlatmayacaktır.

Örtük şablon örneklemeyle ilgili standarttaki ifadeler birçok ayrıntıyı yoruma açık bırakır. Genel olarak, sadece bir şablon parçalarına güvenemez bana görünüyor değil şartname açıkça öyle diyor sürece örneğinin oluşturulmasını. Böylece:

Snippet # 1

S. Bu kod neden derleniyor? B'den miras alırken A'yı somutlaştırmıyor muyuz? B'de VD yoktur, bu yüzden derleyici buraya bir hata atmamalı mı?

Sen somutlaştırıyorsun A<B>. Ancak somutlaştırmak A<B>, statik veri üyelerinin tanımlarını değil, yalnızca bildirimleri somutlaştırır. VBhiçbir zaman bir tanımın var olmasını gerektirecek şekilde kullanılmaz. Derleyici bu kodu kabul etmelidir.

Snippet # 2

S. Neden gcc9 ile derleniyor / neden clang9 ile derlenmiyor?

Jarod42 tarafından işaret edildiği gibi, beyanı ABbir yer tutucu türü içerir. Bana öyle geliyor ki standardın ifadeleri burada ne olması gerektiği konusunda net değil. Bir yer tutucu türü içeren bir statik veri üyesinin bildiriminin başlatılması, yer tutucu türü kesintisini tetikliyor mu ve dolayısıyla statik veri üyesinin tanımını gerektiren bir kullanım mı oluşturuyor? Ben açıkça evet ya da hayır diyebilirim standart ifadeler bulamıyorum. Bu nedenle, her iki yorumun da burada eşit derecede geçerli olduğunu ve dolayısıyla GCC ve clang'ın her ikisinin de doğru olduğunu söyleyebilirim.

Snippet # 3

S. B yapısı burada eksikse neden # 2 snippet'inde eksik değil?

Eğer kapatma ulaşabileceği bir sınıf tipi noktada sadece tamamlandıktan }bir sınıf belirleyici [class.mem] / 6 . Böylece, tüm snippet'lerinizdeki Börtülü örnekleme sırasında eksik olur A<B>. Sadece bu Snippet # 1 için alakasızdı. Snippet # 2'de clang No member named AD in Bsonuç olarak size bir hata verdi. Snippet # 2 örneğine benzer şekilde, tam üye takma ad bildirimlerinin ne zaman somutlaştırılacağına dair ifadeler bulamıyorum. Bununla birlikte, statik veri üyelerinin tanımından farklı olarak, bir sınıf şablonunun örtük olarak başlatılması sırasında üye takma ad bildirimlerinin somutlaştırılmasını açıkça önleyecek bir ifade yoktur. Bu nedenle, hem GCC'nin hem de clang'ın davranışının bu durumda standardın geçerli bir yorumu olduğunu söyleyebilirim…


Teşekkürler. Bu durumda, gövde içindeki statik veri üyesini başlatırız. Başlatma bildirimin bir parçası mı yoksa statik veri üyesi tanımının bir parçası mı? Başlatma gövdenin içindeyse, bu statik veri üyesinin bildiriminin bir parçası olduğu izlenimindeydim. Bildirgenin bir parçasıysa, ilk teklifiniz, sınıf şablonunun çevreleyen örtülü örneğinin bir parçası olarak derhal başlatılmasını gerektirir.
Johannes Schaub - litb

Spec içine baktım ve burada C ++ 14 ve C ++ 17 arasında bir fark var gibi görünüyor. C ++ 14'te constexprstatik veri üyesi yalnızca bir bildirgeydi. C ++ 17 inlinedeğişkenler kazanır ve constexprima eder inline, bu da beden içi statik veri üyesi bildirimini bir tanım yapar.
Johannes Schaub - litb

eel.is/c++draft/dcl.spec.auto#4.sentence-2 "Yer tutucu türü kullanılarak bildirilen bir değişkenin türü, başlatıcısından çıkarılır. Bu kullanıma bir başlatma bildiriminde ([dcl. init]). Bu nedenle, başlatıcıyı içerdiğinden, statik veri üyesinin tanımının gerekli olduğunu iddia ediyorum.
Johannes Schaub - litb

@ JohannesSchaub-litb Bunu incelediğiniz için teşekkürler! Ben de bu soruları merak ediyorum ama kesin bir ifade bulamadım. Başlatma ve tanımlama şeyiyle ilgili olarak, sınıf şablonunun tanımındaki bir üye işlevinin tanımını göz önünde bulundurun. Böyle bir tanım da bir deklarasyon ve başka bir deklarasyon yok. Bununla birlikte, sınıf şablonunun örtülü olarak başlatılması, yalnızca bir bildirimi başlatır, üye işlevinin tanımını değil. Aynı şey statik veri üyeleri için neden doğru olmaz?
Michael Kenzel

tanım gerektiren hiçbir şey yoksa, tanım somutlaştırılmaz. Ancak bu autodurumda kural, bildirimin bir başlangıç ​​bildirimi olması gerektiğini söyler. Bu ancak, bildirimin bir tanım olduğu bilindiğinde geçerli olabilir (bildiğim kadarıyla bir süredir avukatlık arazisinden çıktım). Geçmişte benzer bir durum vardı ve eel.is/c++draft/temp.inst#2.sentence-3 eklendi, burada bir tanım olan bir bildiri, aslında bir tanım olmadan "tanım olarak biliniyor" olarak başlatıldı tanımı somutlaştırmak.
Johannes Schaub -
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.