Program 3 büyük C ++ derleyicisinde farklı şekilde derleniyor. Hangisi doğrudur?


116

Önceki sorumun ilginç bir devamı olarak (yine de büyük bir pratik öneme sahip değil): C ++ neden bir değişken bildirirken değişken adını parantez içine almamıza izin veriyor?

Parantez içindeki bildirimi enjekte edilen sınıf adı özelliği ile birleştirmenin derleyici davranışıyla ilgili şaşırtıcı sonuçlara yol açabileceğini öğrendim .

Aşağıdaki programa bir göz atın:

#include <iostream>
struct B
{
};

struct C
{
  C (){ std::cout << "C" << '\n'; }
  C (B *) { std::cout << "C (B *)" << '\n';}
};

B *y = nullptr;
int main()
{
  C::C (y);
}
  1. G ++ 4.9.2 ile derlemek bana şu derleme hatasını veriyor:

    main.cpp:16:10: error: cannot call constructor 'C::C' directly [-fpermissive]
  2. MSVC2013 / 2015 ile başarıyla derlenir ve baskı yapar C (B *)

  3. Clang 3.5 ve baskılar ile başarılı bir şekilde derlenir C

Öyleyse zorunlu soru hangisi doğru? :)

(Yine de clang sürümüne şiddetle eğildim ve teknik olarak türü değiştirdikten sonra değişkeni bildirmeyi durdurmanın msvc yolu, typedef biraz garip görünüyor)


3
C::C y;mantıklı değil, değil mi? Ne gelmez C::C (y); ilk I azından bu Most-Vexing-Ayrıştırma örneğidir olduğunu düşünmüş stackoverflow.com/questions/tagged/most-vexing-parse , ama şimdi her üç derleyiciler olan anlamı sadece tanımsız davranış olduğunu düşünüyorum "doğru."
Dale Wilson

4
# 3 clang kesinlikle yanlış, # 2 msvc çok müsamahakâr ve # 1 g ++ doğru ((sanırım)

8
C::Cbir türü adlandırmaz, bir işlevi adlandırır, bu nedenle GCC doğru imo'dur.
Galik


Yanıtlar:


91

GCC, en azından C ++ 11 arama kurallarına göre doğrudur. 3.4.3.1 [class.qual] / 2, eğer yuvalanmış isim belirticisi sınıf adıyla aynıysa, enjekte edilen sınıf adına değil kurucuya atıfta bulunacağını belirtir. Örnekler verir:

B::A ba;           // object of type A
A::A a;            // error, A::A is not a type name
struct A::A a2;    // object of type A

Görünüşe göre MSVC, bunu bir yapıcı parametresi olarak geçici bir Cile işlev tarzı atama ifadesi olarak yanlış yorumluyor y; ve Clang bunu ytür adı verilen bir değişkenin bildirimi olarak yanlış yorumlar C.


2
Evet, 3.4.3.1/2 anahtardır. Aferin!
Orbit'te Hafiflik Yarışları

"İşlev adlarının göz ardı edilmediği bir aramada" diyor. Bana öyle geliyor ki verilen örneklerde özellikle A::A a;fonksiyon isimleri göz ardı edilmeli - ya da edilmemeli?
Columbo

1
N4296'daki numaralandırmaya göre, anahtar gerçekten 3.4.3.1/2.1'dir: "eğer iç içe-isim-tanımlayıcısından sonra belirtilen isim, C'de arandığında, C'nin enjekte-sınıf-adı ise [...] ad bunun yerine C sınıfının kurucusunu adlandırdığı kabul edilir. " Yine de Mike'ın özeti biraz fazla basitleştirilmiştir - örneğin, sınıfın içindeki sınıf adının typedef'i, sınıf adından farklı bir iç içe geçmiş ad tanımlayıcısının sınıf adına atıfta bulunmasına izin verir, bu nedenle yine de ctor.
Jerry Coffin

2
@Mgetz: "MSVC2013 / 2015 ile başarılı bir şekilde derleniyor ve baskı yapıyor C (B *)" sorusundan .
Orbit'te Hafiflik Yarışları

2
Eksiksizlik için bu, teşhisin gerekli olup olmadığını veya teşhis gerektirmeden kötü biçimlendirilip biçimlendirilmediğini açıklığa kavuşturmalıdır. İkincisi ise, tüm derleyiciler "doğru" dur.
MM

16

G ++ hata verdiği için doğrudur. Çünkü kurucu, newoperatör olmadan böyle bir formatta doğrudan çağrılamaz. Ve kodunuz çağırsa da C::C, bir kurucu çağrısına benziyor. Bununla birlikte, C ++ 11 standardı 3.4.3.1'e göre, bu yasal bir işlev çağrısı veya bir tür adı değildir ( Mike Seymour'un cevabına bakın ).

Clang yanlıştır çünkü doğru işlevi çağırmaz.

MSVC makul bir şey, ancak yine de standardı takip etmiyor.


2
newOperatör neyi değiştirir?
Neil Kirk

1
@NeilKirk: Bunun new B(1,2,3)geçici somutlaştırmadan B(1,2,3)veya beyandan farklı bir tür "doğrudan kurucu çağrısı" (ki tabii ki öyle değil) olduğunu düşünenler için çok fazla B b(1,2,3).
Orbit'te Hafiflik Yarışları

@LightningRacisinObrit Ne olduğunu nasıl tanımlarsınız new B(1,2,3)?
user2030677

1
@ user2030677: Anahtar sözcük new, tür adı ve yapıcı bağımsız değişken listesi kullanan yeni bir ifade . Hala bir "doğrudan kurucu çağrısı" değil.
Orbit'te Hafiflik Yarışları

"Hatta doğru işlevini çağırmaz beri Clang yanlıştır.": Bence (çünkü beyanlarında parantez hakkında OP'ın sözler) Clang yorumlayabildiğini C::C (y); olarak C::C y;C türü bir değişken y, yani bir tanımı (enjekte C tipi: C :: C'yi kurucu yapan, gittikçe çılgınlaşan dil tanımlamasının 3.4.1,2'sini yanlışlıkla görmezden gelirken). Bu sandığın gibi göze batan bir hata değil, imo.
Peter - Eski Monica
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.