16

İlk bazı kod, bazı bağlam ve ardından soru:Değişkin şablon adlar sonra

template <typename T> using id = T; 

template <template <typename...> class F, typename... T> 
using apply1 = F <T...>; 

template <template <typename...> class F> 
struct apply2 
{ 
    template <typename... T> 
    using map = F <T...>; 
}; 

// ... 

cout << apply1 <id, int>() << endl; 
cout << apply2 <id>::map <int>() << endl; 

clang 3.3 ve gcc 4.8.1 Hem böylece hem int kimlik üst-işlevin uygulayarak hatasız bu derleme ifadeleri varsayılan int (sıfır) olarak değerlendirir.

id bir template <typename>apply1 ederken, apply2 bir template <typename...> ilk etapta endişe bana yaptığı beklemek olması. Ancak, bu örneğin işe yarayacağı oldukça elverişlidir, çünkü apply1, apply2 gibi metafonksiyonlar çok daha fazla dahil edilmelidir.

Diğer yandan, bu tür takma adlar gerçek dünyadaki kodda ciddi şekilde sorun yaratamazlar: burada gcc için sık karşılaşılan derleyici hataları ve daha az sık karşılaşılan beklenmedik davranışlar (yalnızca daha gelişmiş SFINAE testlerinde).

deneme yanılma ay sonra, şimdi yükleyin ve (deneysel) gcc 4.9.0 kod deneyin ve burada hata geliyor:

test.cpp: In instantiation of ‘struct apply2<id>’: 
test.cpp:17:22: error: pack expansion argument for non-pack parameter ‘T’ of alias template ‘template<class T> using id = T’ 
    using map = F <T...>; 
        ^

Tamam, yüzden bu kod değilmiş tüm bu zaman geçerli, ancak gcc hata raporlama yerine çeşitli şekillerde çöktü. İlginç bir şekilde, apply1, apply2 eşdeğer gibi görünürken, hata yalnızca apply2 için bildirilmiştir (bu uygulamada çok daha yararlıdır). Clang gelince, gerçekten söyleyemem. Pratikte, gcc 4.9.0 ile devam etmek ve kodu daha karmaşık hale getirse de düzeltmek için başka bir yolum yok gibi görünüyor.

Teoride, standardın ne dediğini bilmek isterim: bu kod geçerli midir? Değilse, apply1 kullanımı da geçersiz midir? veya sadece apply2?

DÜZENLEME

Hemen yaşadım bütün sorunlar bugüne kadar şablon diğer adları değil, şablon yapılar başvurmak açıklığa kavuşturmak için.

template <typename T> struct id1 { using type = T; }; 

// ... 

cout << typename apply1 <id1, int>::type() << endl; 
cout << typename apply2 <id1>::map <int>::type() << endl; 

Bu clang 3.3, gcc 4.8.1, GCC 4.9.0 üzerine, her iki durumda da 0 ince derler ve baskılar: Örneğin, aşağıdaki modifikasyon düşünün. Çoğu durumda, geçici çözümlerim, diğer addan önce bir ara şablon yapısını tanıtıyor. Üste | Ancak, şimdi, jenerik SFINAE testlerini parametrize etmek için metafonksiyonları kullanmaya çalışıyorum ve bu durumda, doğrudan takma adları kullanmam gerekiyor, çünkü yapıların somutlaştırılmaması gerekiyor. Sadece bir fikir edinmek için, gerçek kodun bir parçası here'dur.

+3

Deneysel GCC 4.9'un hata mesajı bana mantıklı gelmiyor ve FWIW kodun geçerli olduğunu düşünüyorum. –

+0

İlgili? http://stackoverflow.com/q/18724698/420683 – dyp

+0

Teşekkürler, bu soru 'foo', foo2', foo_variadic' gibi özel durumlarla ilgili şablonların tam olarak düzeltmeyi planladığım yollarla ilgilidir. eğer zorundaysam. Ancak, yukarıda düzenlediğim gibi, sorunlarım yalnızca şablon takma adlarıyla görünüyor. – iavr

cevap

3

ISO C++ 11 14.3.3/1:

A template-argument for a template template-parameter shall be the name of a class template or an alias template, expressed as id-expression.

Artı ben variadic şablon şablon parametreleri için herhangi bir özel istisnalar görmüyorum. sorunların

On the other hand, such template aliases cause serious problems in real-world code that I cannot reproduce here: frequent internal compiler errors for gcc, and less frequent unexpected behavior for clang (only in more advanced SFINAE tests).

Kök başka yerlerde olabilir.Dahili derleyici hatasına neden olan kodu yerelleştirmeye çalışmalısınız - sadece ilgisiz parçaları tek tek çıkarın (veya bir çeşit ikili arama, yani böl ve ele geçirme) - ve her aşamada hatanın hala burada olup olmadığını kontrol edin. GCC 4.9.0 hatası gelince


,

template <typename... T> 
using map = F <T...>; 

template <typename... U> 
using map = F <U...>; 

için Belki de bu gördüğü GCC anlamaya yardımcı olacağını değiştirmeyi deneyin.

+0

Teşekkürler. Geçmişte hatalı olan kodu izole edemedim, çünkü küçük parçaların bile kaldırılması hataların ortadan kalkmasını sağladı. Gcc 4.9 ile bu açık bir hata mesajı görebildiğim ilk defa oldu ve ben “mutluydum” çünkü eğer doğruysa, hemen hemen her şeyi açıklayabiliyordu (her çözüm çirkin olsa bile). Her neyse, sorunlar hala orada olduğundan, diğer derleyicilerde beklenmedik bir sonuçla yeni bir örnek oluşturmaya çalışacağım ve yeni bir soruyla geri döneceğim. – iavr