Soru Türü (:: x); geçerli?


Süre tartışılması  Type(identifier); sözdizimi ve nasıl bir beyan olduğunu anladım Type(::x); Clang ile çalışmıyor. Küresel bir değişken verildiğini umuyorum xtedavi olurdu ::x bir ifade olarak (::x + 2 çalışır) ve döküm ::x için Type. Ancak, bir derleyici hatası verir.

Burada kısa bir örnek:

int x;

int main() {
    int(::x); //does not compile
    int(::x + 2); //compiles
}

Clang 3.5 tarafından verilen derleyici hatası:

hata: 'x' tanımı veya yeniden tanımı, global kapsamı isimlendiremez

Ancak GCC 4.9.0, bunu iyi bir şekilde derliyor. Bu kod geçerli mi değil mi?


21
2017-07-08 03:07


Menşei


g ++ 4.8.3 verir error: invalid use of qualified-name '::x' - M.M
@MattMcNabb, "daha yeni" (?) Sürümünün Clang'dan ayrılmasından sonra ilginç. Belki de o zaman 4.9.1'de değiştirilecek. - chris
4.9.1'de neden değiştirilmelidir? - M.M
4.8.3 ile 4.9 arasında değiştiği için, belki de 4.9 için g ++ changelogunda bir şey var. - M.M
@MattMcNabb, 4.8.3 sürüm tarihlerine göre 4.9.0'dan sonra geldi, bu yüzden çok yeni bir şey gibi görünüyor. - chris


Cevaplar:


Bunu anlayabildiğim kadarıyla taslak C ++ standardı Bölüm 8.3  Dectatörlerin anlamı paragraf 6 diyor ki (vurgu ileriye doğru gidiyor):

D'nin formu olduğu T D beyanında

(D1)

İçerilen deklarator kimliğinin türü, içerisindeki declarator kimliğiyle aynıdır.   Deklarasyon

T D1

Parantezler gömülü declarator-id'in türünü değiştirmez, ancak kompleksin bağlanmasını değiştirebilirler   declarators.

yani:

int(::x);

eşdeğerdir:

int ::x ;

Bu açıkça geçerli değildir ve bu da aynı hatayı üretir. Yani gcc 4.9 burada doğru değil ama bu sabit görünüyor çünkü gcc 4.8.3 Daha sonra piyasaya sürülecek olan şey, bunun daha sonraki sürümlerde düzeltilmesini beklerdi. 4.9 de. Her ne kadar bu konuyla ilgili belirgin maçlar görmüyorum gcc 4.8.3 hatalar listesi sabit ama bunun tam bir liste olduğunu iddia etmiyorlar.

İkinci durum, bölüm içerisinde ele alınan işlevsel bir açık tip dönüşümdür. 5.2.3  Açık tip dönüşüm (fonksiyonel gösterim) diyor ki:

Basit tip belirtici (7.1.6.2) veya typename-specifier (14.6)   ardından parantez içinde bir ifade listesi ile bir değer oluşturur   İfade listesi verilen belirtilen tip. İfade listesi bir   Tek ifade, tür dönüşüm ifadesi eşdeğerdir (   tekabül eden ve karşılık gelen kalıba   ifade (5.4). [...]

Bu kesin değil ::x + 2 bir ifade.

Bir beyanın bir bildirim veya ifade olarak kabul edildiği bölümü kapsayan bölüm 6.8  Belirsizlik çözünürlüğü diyor ki:

Dilbilgisinde ifade-ifadeleri içeren bir belirsizlik vardır.   ve bildirimler: Bir işlev stili ile bir ifadesi   En soldaki alt ifadesi olabileceği gibi, açık tip dönüşümü (5.2.3)   İlk declarator'ın başladığı bir bildiriden ayırt edilemez   Birlikte (. Bu durumlarda ifade bir beyannamedir. [ Not tutmak   anlaşmazlık, tüm ifadenin incelenmek zorunda olabilir   bir ifade ifadesi veya beyan olup olmadığını belirleyin. Bu   birçok örneği açıklar.

ve aşağıdaki örnekleri sağlar:

T(a)->m = 7; // expression-statement
T(a)++; // expression-statement
T(a,5)<<c; // expression-statement
T(*d)(int); // declaration
T(e)[5]; // declaration
T(f) = { 1, 2 }; // declaration
T(*g)(double(3)); // declaration

Not: olmadan () sonra T ::D bir nitelikli kimliği bu durumuda T olmak sınıfdilbilgisi içinde kaplıdır 5.1  Birincil ifadeler.

Güncelleştirme

Filed bir gcc hata raporu.

gcc'nin cevabı şu:

Geçerli G ++ ve EDG, her ikisini de geçerli ifade (int) :: x olarak ele alır.

Bu yanıtın ima ettiği için clang yanlış(Yine de kabul etmiyorum), Bir dosyaladım clang bug raporu ve eski hata raporu benzer görünüyor ve gcc tepki.

2. Güncelleme

Yanıt olarak clang bug report Richard Smith bunun bir deklarasyon olarak ele alınması gerektiğini söylüyor ve şöyle diyor:

Bu, clang'ın yanlış olduğunu ima etmez; Aslında, Clang doğru   Burada görebildiğim kadarıyla. (Ayrıca EDG'ye bir hata raporu gönderdim.)

Doğru bir şekilde vermeliyiz 'bir çırpınan parse vurdunuz, işte nasıl gidiyor?   Bu durumda 'hatayı bertaraf etmek için.

3'ü güncelle

gcc  dogruluyor bu bir böcek.


18
2017-07-08 03:41



Bildirimin geçersiz olduğuna bakılmaksızın bunun bir ifadeden ziyade bir beyan olarak ele alınması gerektiğini söyleyen kısmı biliyor musunuz? P.S., hata yapar değiştirirseniz struct Foo {}; tür olarak kullanılır :) - chris
"İçinde deklarasyon T D "(Vurgula). Bunu kurmak zorundayız. int (::x); Bu maddeden önce bir beyanname belirtilebilir. - M.M
Foo::x; ve Foo (::x); farklı hatalar vermek Foo bir sınıftır. - M.M
@MattMcNabb, çünkü Foo ::x Alan kaldırılır ve nitelikli bir kimlik olarak kabul edilir. - Shafik Yaghmour
@MattMcNabb fyi, gcc bu bir hata olduğunu onayladı - Shafik Yaghmour


Bu benim için en çok rahatsız edici ayrılık gibi görünüyor. Bir deklerasyon olarak ayrıştırılabilirse bu olacaktır. İlk bir int değişkeni beyanı olarak ayrıştırılabilir (int ::x;), ama :: bu bağlamda yasa dışıdır. İkinci vardır bir ifade ve böylece derleyici matematik yapar, onu int yapar ve sonucu atar.

Bu bilgi veren bir soru muydu yoksa başka bir sorun mu var? Çözmeyi denediğiniz belirli bir sorununuz varsa, ek bilgiler kullanım durumunuz için bir geçici çözüm sağlar.


11
2017-07-08 03:23



@Matt McNabb Bu sadece C ++ dilinin çalıştığı yoldur. İhtiyacımız olan aynı sebep typename şablonlar için anahtar kelime. - Mark B
Ne olduğunu açık değilim int::x; olması gerekiyordu. Foo::x; bakmak istiyorum x Kapsamında Foove bu bir beyan değil. Öyle görünüyor int::x; farklıdır int(::x); - M.M
İlginç. Geçerli bir ifadeyle hala geçerli olan geçersiz bir beyanın farkında değildim. - chris
@MarkB İhtiyacımız var typename Bir tanımlayıcının bir tür veya değişken tanımlayıp tanımlamadığını belirtmek için. Bunun davaya nasıl benzediğini anlamıyorum int (::x); . Kural ise eğer sözdizimsel bir deklarasyon olarak geçerli olduğu zaman bir deklarasyondur (bir deklarasyon olarak da kötü biçimlendirilmiş olsa bile). Ancak nasıl göremiyorum int (::x); (blok kapsamında) bir beyanname için geçerli bir sözdizimidir. - M.M