Sınıfım neden varsayılan olarak oluşturulamıyor?


28

Şu sınıflarım var:

#include <type_traits>

template <typename T>
class A {
public:
    static_assert(std::is_default_constructible_v<T>);

};

struct B {
   struct C {
      int i = 0;
   };

    A<C> a_m;
};

int main() {
    A<B::C> a;
}

Derleme yapılırken, a_mvarsayılan olarak oluşturulamaz ancak a.

Olarak değiştirirken C:

struct C {
      int i;
   };

herşey yolunda.

Clang 9.0.0 ile test edilmiştir.


3
GCC 8.3 - TAMAM, GCC 9.1 / 9.2 - Başarısız.
Evg

2
Bununla birlikte C() {}de çalışır.
Evg

3
Bu bana çok kötü kokuyor. Bugzilla'da hemen maç yok.
Yörüngedeki Hafiflik Yarışları

2
İlginç: static_assertin Abaşarısız olur, ancak bunun yerine varsayılan olarak bir TA(örneğin bir üye koymak T t;) inşa ederseniz , her şey yolunda çalışır. Tip özelliğinin size söylediği ile aslında neyin mümkün olduğu arasında bir tutarsızlık ...
sebrockm

2
@Nicolas True, ancak bunun nedeni, hiçbiri burada geçerli olmayan bazı kenar durumlar nedeniyle (özellikle cppreference'deki aynı cümlenin söylediği gibi, const int x;bir başlatma aracı olmadan geçersizdir, yalnızca constyerleşik türlerin ve bazılarının başlatma davranışlarından dolayı geçmişi)
Yörüngedeki Hafiflik Yarışları

Yanıtlar:


9

Bu, hem standardın metni hem de yorumlarda belirtildiği gibi birkaç önemli uygulama tarafından, ancak tamamen ilgisiz nedenlerle izin verilmez.

İlk olarak, "kitaba göre" nedeni: nesnelleştirilmesi noktası A<C>olduğunu standardına göre, hemen tanımına önceB ve nesnelleştirilmesi noktası std::is_default_constructible<C>olduğunu hemen önce geçerli:

Bir sınıf şablonu uzmanlığı için, [...] uzmanlık başka bir şablon uzmanlığından başvurulduğu için dolaylı olarak somutlaştırılırsa, uzmanlığa atıfta bulunulan bağlam bir şablon parametresine bağlıysa ve uzmanlık daha önce somutlaştırılmamışsa çevreleme şablonunun somutlaştırılması için, somutlaştırma noktası, mahfaza şablonunun somutlaştırılmasından hemen önce olmaktadır. Aksi takdirde, böyle bir uzmanlık için örnekleme noktası, uzmanlaşmayı ifade eden ad alanı kapsamı bildiriminden veya tanımından hemen önce gelir.

Yana Cbu noktada açıkça eksiktir, nesnelleştirilme davranışı std::is_default_constructible<C>tanımsızdır. Ancak, bu kuralı değiştirecek olan 287 numaralı temel meseleye bakınız .


Gerçekte, bunun NSDMI ile ilgisi vardır.

  • NSDMI'ler, ayrıştırmayı geciktirdikleri için gariptir - ya da standart olarak "tam sınıf bir bağlam" dır.
  • Bu nedenle, = 0ilke olarak Bhenüz bildirilmemiş şeylere atıfta bulunabilir , bu yüzden uygulama bitene kadar gerçekten ayrıştırmayı deneyemez B.
  • Bir sınıfın tamamlanması, bildirilmiş bir kurucuya sahip olmadığından özel üye işlevlerinin, özellikle de varsayılan kurucunun örtülü olarak bildirilmesini gerektirir C.
  • Bu bildirimin bazı bölümleri (sürekli, önemsiz) NSDMI'nın özelliklerine bağlıdır.
  • Bu nedenle, derleyici NSDMI'yi ayrıştıramazsa, sınıfı tamamlayamaz.
  • Sonuç olarak, somutlaştığı noktada bunun eksik A<C>olduğunu düşünür C.

Gecikmiş ayrışmış bölgelerle ilgilenen bu alan, beraberinde uygulama ayrışması ile birlikte yetersiz bir şekilde daha az belirtilmiştir. Temizlenmesi biraz zaman alabilir.


0

Tanımsız davranış :

Yukarıdaki bir şablonun örneklenmesi doğrudan veya dolaylı olarak eksik bir türe bağlıysa ve bu tür varsayımsal olarak tamamlandıysa bu örnekleme farklı bir sonuç verebilirse, davranış tanımsızdır.


7
C neden eksik?
interjay

1
@interjay, Ctamamlandı, ama Bdeğil. Ve B::Cdolaylı olarak bağlıdır B.
Evg

1
@Evg "Doğrudan veya dolaylı olarak değişir" metni yalnızca cppreference.com sitesinde görünür. Standart sadece T tipinin tamamlanması gerektiğini söylüyor.
interjay


2
@interjay Bu ifadelerin çoğunu yazdım. Söylemeye çalıştığımız şey şudur: 1) daha sonra bazı eksik türler tamamlandığında bir ODR ihlaline neden olabilecek bir özellik başlatırsanız, bu tanımsızdır; ve 2) programınızda gerçekten bir ODR ihlaline neden olmasanız bile tanımsızdır , böylece standart kütüphane uygulamaları, arzu ettikleri anda özelliğin kullanıldığı noktayı teşhis etmeyi seçebilir. Eğer Cvarsa cevapları değiştirebilir bazı garip SFINAE ile varsayılan yapıcı şablonu olan Btamamlandıktan farklı, daha sonra emin, özellik buna bağlıdır.
TC
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.