Sorun, SFINAE'ye dayanmaktadır. Eğer üye işlev value_t<S<T>>
olmak yeniden Eğer dış beyanı gibi, o GCC mutlu derlemeyi yapacaktır: ifadesi şimdi işlevsel eşdeğerdir
template<class T>
struct S
{
using value_type = int;
static const value_t<S<T>> C = 0;
};
template<class T>
const value_t<S<T>> S<T>::C;
çünkü. değiştirilme hatası gibi şeyler alias-templates üzerinde oynamak gel, ama görebildiğiniz gibi, value_type const C
üye işlevi value_t<S<T>> const S<T>::C
olarak "prototype" olarak yok. Birincisi SFINAE'yi yapmak zorunda değilken, ikincisi bunu gerektirir. Açıkça, her iki deklarasyonun da farklı işlevleri vardır, dolayısıyla GCC'nin tantrumu. İlginçtir ki, Clang bir anormallik belirtisi olmadan derler. Ben de öyle düşünüyorum ki, Clang analizlerinin sırası GCC'lere kıyasla tersine çevrilir. Takma-şablon ifadesi çözüldükten ve iyi olduğunda (yani iyi biçimlendirilmişse), clang her iki bildirimi de karşılaştırır ve eşdeğer olduklarını kontrol eder (bu durumda, her iki ifade de value_type
olarak çözülür).
Şimdi, standart gözlerden hangisi doğrudur? Bu, takma adın işlevselliğinin bir parçası olarak takma adın şablonunun SFNIAE'sini göz önünde bulundurup düşünmemesi hâlâ çözülmemiş bir sorundur. [temp.alias]/2 alıntı:
şablon kimliği bir takma şablonun uzmanlık belirtir
, bu tip-id şablon parametreleri için kalıptan bağımsız değişken ile yer değiştirmesi sonucu elde edilen ilişkili türü için eşdeğerdir takma ad şablonu. Diğer bir deyişle,
, bu iki eşdeğerdir: ikame gerçekleştirildikten sonra, her iki tip vector<int, Alloc<int>>
olarak sona için
template<class T>
struct Alloc { /* ... */ };
template<class T>
using Vec = vector<T, Alloc<T>>;
Vec<int> v;
vector<int, Alloc<int>> u;
Vec<int>
ve vector<int, Alloc<int>>
eşdeğer türleridir. "İkame sonrası" ifadesinin, denklemin sadece tüm şablon argümanlarının şablon parametreleri ile değiştirilmesinden sonra kontrol edilmesi anlamına geldiğini unutmayın. Yani, vector<T, Alloc<T>>
'daki T
, Vec<int>
'dan int
ile değiştirildiğinde, karşılaştırma başlar. Belki de bu Clang value_t<S<T>>
ile yapıyor?Ama sonra [temp.alias]/3 Aşağıdaki alıntı var: şablon kimliği bağımlı olup olmadığını
Ancak, daha sonraki şablon argümanı ikamesi hala şablon id için de geçerlidir. [Örnek:
template<typename...> using void_t = void;
template<typename T> void_t<typename T::foo> f();
f<int>(); // error, int does not have a nested type foo
- uç örneği]: ifade iyi oluşturulmuş olması sahiptir, böylece derleyici ikame iyi olup olmadığını kontrol etmek için ihtiyaç
Burada sorun. Şablon argüman ikamesini (ör. typename T::foo
) gerçekleştirmek için bir bağımlılık olduğunda, tüm ifadenin işlevselliği değişir ve "eşdeğerlik" tanımı farklıdır. Dış foo
sitesindeki prototip iç bir işlevsel olarak farklı olduğu için
struct X
{
template <typename T>
auto foo(T) -> std::enable_if_t<sizeof(T) == 4>;
};
template <typename T>
auto X::foo(T) -> void
{}
: Örneğin, aşağıdaki kodu (GCC ve çınlama) derlenmeyecektir. Bunun yerine auto X::foo(T) -> std::enable_if_t<sizeof(T) == 4>
yapmak, kodun düzgün bir şekilde derlenmesini sağlar. Bunun nedeni, foo
dönüş türünün sizeof(T) == 4
sonucuna bağlı bir ifadedir, bu nedenle şablon değiştirilmesinden sonra, prototipinin her örneği farklı olabilir. Oysa, auto X::foo(T) -> void
'un dönüş tipi asla farklı değildir, bu da X
içindeki bildirimle çakışır. Bu, kodunuzda gerçekleşen aynı sorun. Yani GCC bu durumda doğru gibi görünüyor.
Eşdeğer olması gerektiği gibi görünüyor: http://eel.is/c++draft/temp.alias#2 – Barry
500 için derleyici hatası ile gideceğim, Alex – AndyG
Ben o kadar önemsiz olduğunu düşünmüyorum . Takma adlara ilişkin bağımlı türlerin denkliği hakkında birçok soru var. Http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1979 ve bununla bağlantılı olan tüm konulara bakın. Bir cevap bu soruyu ve bu konuların konuyla ilgisini, IMO'yu kapsamalıdır. –