5

tanımsız alt tip erişildiğinde hata iletisi derleme: kullanılan bu alt türü var ama yokÖzel Ben aynı adla alt türleri her olan bazı türlerine sahip

struct TypeA { 
    typedef int subtype; 
}; 
struct TypeB { 
    typedef float subtype; 
}; 

ve ayrıca tiplerini

struct TypeC { 
    // (no subtype defined) 
}; 

Nasıl özel hata mesajı derlemek veren bir kukla alt türünü ekleyebilirsiniz: aynı bağlamda?

Benim (şimdiye kadar başarısız) girişimdir:

struct TypeC { 
    struct subtype { 
     static_assert(false, "Attempt to access the non-existent subtype of TypeC."); 
    }; 
}; 

Ama static_assert(false, ...) çalışamaz, derleyici tür erişilen asla bile hata atar olarak.

Türün erişilebilir olduğu zamana kadar static_assert değerlendirmesini nasıl geciktirebilirim?

enum { X }; 
static_assert(X != X, "..."); 

beton kullanım durumunda: bir alt tanımlanan bir sınıf şablon List sahip

bir girişimi bunun dışında bir ifade, bir sahte enum tanıtmak ve inşa etmektir başarısız tipleri head ve tail boş olmayan ise, bu alt tipleri kullanılırsa o boşsa bir hata vermelidir:

template<typename...> 
struct List; 

// empty list: 
template<> 
struct List<> { 
    struct head { static_assert(false, "Attempt to access the head of an empty list."); }; 
    struct tail { static_assert(false, "Attempt to access the tail of an empty list."); }; 
}; 

// non-empty list: 
template<typename Head, typename ...Tail> 
struct List<Head, Tail...> { 
    typedef Head head; 
    typedef List<Tail...> tail; 
}; 

Yalnızca head ve tail türlerini, örn. koduyla List<int,int>::tail::tail::head ile büyüklüğü 2 olan bir listenin 3 eleman (g ++ 4.7.2) öylesine güzel mesaj veriyor: 'head' is not a member of 'List<int>::tail {aka List<>}'

+0

Bu 'List <>' örnek 'static_assert's hakkında şikayet etmiyor? Derhal değerlendirmeyi önlemek için şablon parametresi içermesi gereken sürekli ifadeyi düşündüm. – aschepler

+0

Hmm, kukla enum [işe yaramıyor] (http://coliru.stacked-crooked.com/a/602ff84bdc70c08e) ya da. –

+0

@aschepler Diğer derleyicilerden ve hatta standartlardan emin olmadığından g ++ 4.7.2 ile çalışır. – leemes

cevap

5
// empty list: 
template<typename... Args> 
struct List { 
    struct head {static_assert(sizeof...(Args) != 0, "Attempt to access the head of an empty list."); }; 
    struct tail {static_assert(sizeof...(Args) != 0, "Attempt to access the tail of an empty list."); }; 
}; 

// non-empty list: 
template<typename Head, typename ...Tail> 
struct List<Head, Tail...> { 
    typedef Head head; 
    typedef List<Tail...> tail; 
}; 

Düzenleme: Bu sorun aslında C++ şablonları nasıl çalıştığını üç cepheden dokunuyor:

  1. (§14.7.1 [temp.inst]/p1), bir sınıf şablonu uzmanlık açıkça örneği olmuştur sürece (14.7.2) ya da açıkça uzmanlaşmış (14.7.3), sınıflandırma şablonu uzmanlığı, tamamen tanımlanmış bir nesne türü gerektiren veya sınıf türünün tamlığı programın anlamını etkilediğinde, uzmanlık başvurusu yapıldığında örtük olarak başlatılır.Bir sınıf şablon uzmanlığının örtük bir örneği, sınıf üyelerinin işlevlerinin, üye sınıflarının tanımlarının… değil, bildirimlerin örtük bir örneğine neden olur [...].
  2. (§14.7.1 [temp.inst]/p11) Bir uygulama, somutlaştırmayı gerektirmeyen bir sınıf şablonunun ... bir üyesi sınıfını ... örtük olarak başlatmaz.
  3. (§14.6 [temp.res]/p8) Şablon için geçerli bir uzmanlık oluşturulamadıysa ve bu şablon örneklenmemişse, şablon bozuk biçimlidir, tanı gerekmez.

3) aksi takdirde "geçerli bir uzmanlık" şablon için oluşturulabilir ve program kötü oluşturulur olarak static_assert sentezleme, bir şablon argüman bağlıdır gerektiği anlamına gelir, ve derleyicilerinin rapor serbesttir hata (zorunda olmasa da). Yukarıdaki kodda, ilk şablon için geçerli bir uzmanlık oluşturulabilir, ancak kısmi uzmanlaşma nedeniyle böyle bir uzmanlık asla kullanılmaz. Yukarıda verilen çözüm ayrıca 1) ve 2) 'ye dayandırılmaktadır. 1) dolaylı başlatmasını bir şablon uzmanlık sadece Deklarasyonları elemanı sınıflarının (değil tanımları) başlatır öngörmektedir, ve 2) sadece bir dolaylı List<> örneği kullanarak derleyici olumlu head veya eğer biri tail örneğini girişiminde yasaklanmıştır demektir . 'u template struct List<>; ile açıkça başlatırsanız bu kuralın geçerli olmadığını unutmayın.

typedef ler tam bir türü gerektirmeyen ve böylece 1'in altında SubTypeErrorMessage<> zımni başlatamaması tetiklemek yok çünkü leemes yanıtında çözelti) çalışır ve SubTypeErrorMessage yılında static_assert bir şablon argüman kullanımı gibi) 3 atlar Bu şablon için geçerli uzmanlık (yani, SubTypeErrorMessage<true>) oluşturulabilir.

Her iki durumda da, örnekleme kuralları, tam bir tür gerektiren bir şekilde kullanmadığınız sürece List<>::head veya TypeC::subtype'u kullanmanın hala yasal olduğu anlamına gelir. Bu nedenle, int f(List<>::head &) { return 0; } gibi bir şey geçerli olsa da, aslında tamamen anlamsızdır, çünkü aslında bu işlevi çağırmanın bir yolu yoktur. Ancak, List<>::head'u tanımlamıyorsanız, derleyici bu kodda bir (belki de şifreli) hata bildirecektir. Yani bu daha güzel hata iletileri için trade-off'tır :)

+0

Ah güzel olan, ifade içinde "doğru mantık" bile var;) (daha büyük bir büyüklükte 0 olan olgular asla ona ulaşmıyor ...) Bu güzel çözüm için – leemes

+0

Detaylı açıklamanız için çok teşekkür ederim. Özetlemek gerekirse, hem sizin hem de çözümümün işe yaraması garanti ediliyor, yani derleyicinin iddia etmesini istediğimden daha erken değerlendirmesine izin verilmiyor mu? – leemes

+0

@leemes Bence öyle. –

5

senin tipin erişilen noktaya static_assert değerlendirmesini geciktirmek için, gerek ifadesini şablon parametresine bağlı hale getirin.

template<bool X = false> 
struct SubTypeErrorMessage { 
    static_assert(X, "Attempt to access the non-existent subtype of TypeC."); 
}; 

Ardından, olmasını istediğiniz somut türü:

Olası bir çözüm (şablon parametresinin değerine bağlı olarak) sadece şartlı hata mesajı yazdırmak için bir yardımcı sınıf şablonu eklemektir bir "kukla alt türü":

struct TypeC { 
    typedef SubTypeErrorMessage<> subtype; 
}; 

Live Demo

İlgili konular