sınıf şablonları tanımlanan friend
fonksiyon şablonları ile ilgili iki çözülmemiş sorunlar vardır: 1545 ve 2174. Eski, geçerli olanın ne ölçüde geçerli olduğunu sorguluyor ve ikincisi, bu işlev şablonlarının gerçek örneklemelerine dayanarak ortaya çıkabilecek ihlal ihlalleri hakkında. Hangi derleyicinin doğru olduğundan emin değilim (daha önce her ikisinin de yanlış olduğuna inanmış olmakla birlikte), ancak standart olarak bu davranışta doğru davranışın ne olduğu konusunda yetersiz ya da zayıf olarak belirtilebilir.
ideal (sorun çözümünü bekliyor) derlemek gerekir kod:
template<typename ...Args>
class obj {
bool p = false;
template<typename T, typename... Args2>
friend T get(const obj<Args2...> &o) { return o.p; }
};
template<typename T, typename... Args>
T get(const obj<Args...> &o);
friend
beyan ilk get
beyan, bu nedenle bu en iç kapsayan ad alanının yeni bir üye oluşturur: ::get
. Harici bildirim sadece aynı işlevi tekrarlar, yani gerçekten sadece bir tane ::get
. [Temp.over.link] Gönderen:
şablon parametrelerini içeren iki ifadeler eşdeğer kabul edilmektedir
eğer hariç, tek tanımlı kural (3.2) tatmin edecek ifadeleri içeren iki fonksiyon tanımları olduğunu adlandırmak için kullanılan jetonları şablon parametreleri, bir ifadede bir şablon parametresini adlandırmak için kullanılan bir belirteç olduğu sürece, diğer ifade içinde aynı şablon parametresini adlandıran başka bir jetonla değiştirilen farklı olabilir. İki bağımlı adın (14.6.2) eşdeğer olup olmadığını belirlemek için öğesinin belirlenmesi için, yalnızca şablonun adı dikkate alınmaz, şablon bağlamında ad arama sonucunun sonucudur. Farklı şablon parametre adları (Args2...
vs Args...
) kullanarak
gayet - fonksiyon şablonun ::get
bu ikinci beyanı geçerlidir ve onu bulmak için arama için izin verir.
Bu bize getiriyor:
bool test(const obj<int, float, double> &a) {
#ifdef UNQUAL
return get<int>(a); // unqualified
#else
return ::get<int>(a); // qualified
#endif
}
bu gerektiği işin Hem - biz ad kapsamında olması işlevini redeclared beri, hatta ADL konusunda endişelenmenize gerek yoktur.Her iki çağrı da friend
olan ::get<int>(obj<int, float, double>)
'u bulmalı ve böylece kod derlenmeli ve bağlanmalıdır. gcc vasıfsız çağrıya izin verir, ancak nitelikli çağrıya izin vermez, clang ikisine de izin vermez.
Biz sadece değil sınıf içinde işlev şablonu tanımlayarak tamamen CWG sorunlarını hem sidestep: Bu formülasyon ile
template<typename ...Args>
class obj {
bool p = false;
template<typename T, typename... Args2>
friend T get(const obj<Args2...> &o);
};
template<typename T, typename... Args>
T get(const obj<Args...> &o) { return o.p; }
, hem derler get
ait nitelikli ve niteliksiz çağırma hem izin verir.
biz obj
bir sınıf değil, bir sınıf şablonu olacak şekilde kod, ancak tüm şey eşit olduğunda yeniden edin:
class obj {
bool p = false;
template <class T>
friend T get(const obj& o) { return o.p; }
};
template <class T> T get(const obj&);
bool test(const obj& a) {
#ifdef UNQUAL
return get<int>(a);
#else
return ::get<int>(a);
#endif
}
Her iki derleyiciler hem çağırmaları izin verir. Ancak, normal sınıf ve sınıf sınıfı olan obj
arasındaki kurallarda farkında olduğum hiçbir fark yoktur.
sen ... denemek yoksa çalışmıyor Çünkü 'şablon T olsun (const obj &o);' dışında sınıf –
Jarod42
ilan Neden:? Https://godbolt.org/g/peSscU –
Evet, "T", "" değerini sağlamanız gerektiğinden, ADL çalışmaz (global kapsamda "get" şablonu olmadığı için): ADL'yi yeniden etkinleştirmek için kukla bir şablon almanızın (doğru eşleşmeyle) bildirilmesi: [Demo] (http://coliru.stacked-crooked.com/a/e40aaf90de712943) –
Jarod42