Bu sorun açıklamak biraz zor, bu yüzden bir örnekle başlayacak: Bir tür ve şablon parametreleri olarak sabit bir tamsayı alan bir sınıf şablonu varŞablon uzmanlık
ve o şablonun örneklemesi kaynaklanıyor çocuk sınıfları bir dizi var:
template <class V, int i>
struct Base
{
static void doSomething() { cout << "something " << i << endl; };
};
struct Child : public Base<int,12>
{
};
bazı diğer şablonu ile bu sınıfları kullanmak istediğiniz farklı türleri için uzmanlık sahip olan (en Testi diyelim). Davranış, Base'in herhangi bir örneğinden türetilen tüm sınıflar için tam olarak aynı olması gerektiğinden, yalnızca Temel'den türetilen tüm sınıfları işleyen tek bir Uzmanlık özelleştirme tanımlamak istiyorum.
Temel olarak, bu alt sınıfları algılayamayacağından, < V, i > numaralı Temel için uzmanlaşamayacağımı biliyorum. Bunun yerine, benim ilk yaklaşım Boost enable_if ve tip özellikleri kullanıyordu:
// empty body to trigger compiler error for unsupported types
template <class T, class Enabled = void>
struct Test { };
// specialization for ints,
// in my actual code, I have many more specializations here
template <class Enabled>
struct Test <int, Enabled>
{
static void test (int dst)
{
cout << "Test<int>::test(" << dst << ")" << endl;
}
};
// this should handle all subclasses of Base,
// but it doesn't compile
template <class T, class V, int i>
struct Test <T, typename enable_if <is_base_and_derived <Base <V,i>, T>>::type>
{
static void test (const T &dst)
{
dst.doSomething();
}
};
int main (int argc, char **argv)
{
Test <int>::test (23);
Test <Child>::test (Child());
return 0;
}
fikri uzmanlık V ve i herhangi keyfi değerlerle Base türetilen tüm sınıfları işlemek gerektiği şeklindeydi. Bu işe yaramazsa, gcc yakınır:
error: template parameters not used in partial specialization: error: ‘V’ error: ‘i’
Sorun bu yaklaşım V tüm olası kombinasyonları denemek derleyici gerektirecektir ve bunlardan herhangi eşleşirse ı kontrol etmek olduğunu tahmin ediyorum.
template <class V, int i>
struct Base
{
typedef V VV;
static constexpr int ii = i;
static void doSomething() { cout << "something " << i << endl; };
};
Bu şekilde, uzmanlaşma artık V olması gerekir ve ben serbest şablon parametreleri:
template <class T>
struct Test <T, typename enable_if <is_base_and_derived <Base <typename T::VV, T::ii>, T>>::type>
{
static void test (const T &dst)
{
dst.doSomething();
}
};
Sonra Şimdilik, ben temel sınıf için bir şeyler ekleyerek bu sorunu çalıştı derler.
Şimdi, sorum şu: Temel sınıfı değiştirmeden bunu nasıl yapabilirim? Bu durumda, kendim yazdığım için mümkün oldu, ancak Test şablonumda üçüncü taraf kitaplık kodunu işlemek zorunda kalırsam ne yapabilirim? Daha şık bir çözüm var mı?
Düzenleme: Birisi bana tam olarak ilk yaklaşımın neden çalışmadığını ayrıntılı bir açıklama verebilir mi? Zor bir fikrim var, ama doğru bir anlayışa sahip olmayı tercih ederim. :-)
basit bir çözümBase
izin vermektir
Base_Base ipucu için teşekkürler, bu benim mevcut kodumu biraz daha okunabilir kılıyor. Ancak, üçüncü parti kütüphaneler için, bu çalışma, en azından çocuk sınıfları da kütüphaneye ait değilse işe yaramaz. –
@BenjaminSchug: belki de [this] (http://stackoverflow.com/a/6398983/1324131) yeni sorunuzu düzenlenmiş soruda cevaplıyor. – user2k5
Teşekkürler, bu, ilk yaklaşımın neden çalışmadığını açıklıyor.Benim bağırsak hislerimin doğru olması gibi görünüyor. –