2011-04-14 23 views
23

Aşağıdaki sınıfı göz önünde bulundurun: iç yapısı Y tür olarak kullanılıyor, örn. daha sonra şablonları, içinde: Koşullu derleme zamanı şablon argümanlarına dayalı kodun eklenmesi/hariç tutulması?

template<int I> 
class X{ 
    template<class T1> 
    struct Y{}; 

    template<class T1, class T2> 
    struct Y{}; 
}; 

Şimdi, bu örnek açıkça ikinci X<I>::Y zaten tanımlı edildiğini hata ile, derlemek ya da çok sayıda şablon parametresi vardır olmayacaktır.
int I parametresi yalnızca bir tane değil ve onun konumu farklı kısmi uzmanlıklarda farklılık gösterebileceğinden (ek) kısmi uzmanlık olmadan bunu çözmek istiyorum (benim gerçek yapım more like this olarak görünüyor, yukarıdaki sadece basitlik içindir) soru), bu yüzden one class fits every I çözümü istiyorum.


ilk düşüncem açıkçası enable_if, ama bu, bana mesela başarısız gibi görünüyor. Ben hala aynı hataları alıyorum:

template<int I> 
class X{ 
    __include_if(I == 1){ 
    template<class T1> 
    struct Y{}; 
    } 

    __include_if(I == 2){ 
    template<class T1, class T2> 
    struct Y{}; 
    } 
}; 

Sadece olurdu: enable_if başarısız beri

// assuming C++11 support, else use boost 
#include <type_traits> 

template<int I> 
class X{ 
    template<class T1, class = std::enable_if<I==1>::type> 
    struct Y{}; 

    template<class T1, class T2, class = std::enable_if<I==2>::type> 
    struct Y{}; 
}; 

yani, ben şu derleme zamanı kontrol ulaşmak için başka bir yol yoktur umut kod çoğaltmanın bir çok kurtarmak için olmak, ama bir şekilde mümkün olsaydı gerçekten çok mutlu olurdum.
Düzenleme: Ne yazık ki, Visual Studio 2010 kullandığım gibi, bariz: variadic şablonları kullanamıyorum, bu yüzden yalnızca orada desteklenen desteklenen C++ 0x şeyler. :/

+0

+1. İlginç soru. Ofis saatinden sonra cevap vermeye çalışacağım: D – Nawaz

+0

Zevkle bekliyorum. :) Düşünce çizgim, derleyicinin bilmesi gereken herşeyi iyi bildiği gibi derlemenin mümkün olması gerektiğidir. – Xeo

+0

@Xeo: C++ 0x özelliklerini kullanabiliyor musunuz? – Nawaz

cevap

8

Burada iki sorun vardır: kısmi uzmanlaşma, birincil olmayan şablonlarla

  1. enable_if çalışır.
  2. Dıştan görünen değişkenlerin sayısı, yalnızca bir tane olabileceği birincil şablon tarafından belirlenir. Eğer sohbet önerildiği gibi

Cevap 1.

, şablonlar bağlantılı liste variadic parametre paketi taklit edebilir. Eğer next::next::next çöp ile bitirmek durumunda

template<int I> 
class X{ 
    template<class list, class = void> 
    struct Y; 

    template<class list> 
    struct Y< list, typename std::enable_if<I==1>::type > { 
     typedef typename list::type t1; 
    }; 

    template<class list> 
    struct Y< list, typename std::enable_if<I==2>::type > { 
     typedef typename list::type t1; 
     typedef typename list::next::type t2; 
    }; 
}; 

, bir üst-işlevin yazmak veya Boost MPL kullanımı kolaydır.


Cevap 2.

farklı-Arity şablonları benzer adlandırılmış ancak SFINAE kontrollü tip iç içe olduğu takdirde yine ayrı kalmak edilebilir.

template<int I> 
class X{ 
    template<typename = void, typename = void> 
    struct Z; 

    template<typename v> 
    struct Z< v, typename std::enable_if<I==1>::type > { 
     template<class T1> 
     struct Y{}; 
    }; 

    template<typename v> 
    struct Z< v, typename std::enable_if<I==2>::type > { 
     template<class T1, class T2> 
     struct Y{}; 
    }; 
}; 

X<1>::Z<>::Y<int> a; 
X<2>::Z<>::Y< char, double > b; 
+0

Efendim, "enable_if, kısmi uzmanlık ile çalışır, birincil şablonlar değil." Neden OP'nin yaptığı gibi birincil şablonla kullanamazsın? Çok teşekkürler :) –

+1

@AngelusMortis Kısmi uzmanlık şablon parametreleri çıkarıldı (§14.5.5.1 [temp.class.spec.match]). 'enable_if' orada çalışmaktadır, çünkü İkame Arızası kesinti dahilinde bir Hata (SFINAE) değildir. Birincil şablonlar bu faydaya sahip değildir - ikame hatası bir hatadır. – Potatoswatter

0

Bu yaklaşım nasıl yapılır - http://sergey-miryanov.blogspot.com/2009/03/template-class-overriding.html? (Rusça için üzgün)

+0

Ne yazık ki uygulanamaz, çünkü iç şablon yapısı, örneğin, şablonlarda kullanılmalıdır. :/ – Xeo

+0

Btw, [burada google çevrilmiş site] (http://translate.google.de/translate?js=n&prev=_t&hl=de&ie=UTF-8&layout=2&eotf=1&sl=ru&tl=tr&u=http%3A Niyeti ikiye katlayan% 2F% 2Fsergey-miryanov.blogspot.com% 2F2009% 2F03% 2Ftemplate-class-overriding.html & act = url). – Xeo

+0

İkinci bir düşüncede, belki bu bazı decltype hileleriyle işe yarar. Eve döndüğümde deneyeceğim. :) – Xeo

1

aşağıda denemek Can (kısmi uzmanlaşma değil):

template<int I> 
class X 
{ 
}; 

template<> 
class X<1> 
{ 
    template<class T1> 
    struct Y{}; 
}; 

template<> 
class X<2> 
{ 
    template<class T1, class T2> 
    struct Y{}; 
}; 

Cevabın basit olduğunu ise şüphe !!

Düzenleme (Kısmi ihtisas alaycı): @Xeo, ben aşağıdaki kodu derlemek başardı ve fullfilling gibi görünüyor. İşte

template<int I> 
struct X 
{ 
    struct Unused {}; // this mocking structure will never be used 

    template<class T1, class T2 = Unused> // if 2 params passed-->ok; else default='Unused' 
    struct Y{}; 

    template<class T1> 
    struct Y<T1, Unused>{}; // This is specialization of above, define it your way 
}; 

int main() 
{ 
    X<1>::Y<int> o1; // Y<T1 = int, T2 = Unused> called 
    X<2>::Y<int, float> o2; // Y<T1 = int, T2 = float> called 
} 

, ancak < 1> X < 2> birbirinin yerine X kullanabilirsiniz. Fakat bahsettiğiniz daha geniş örnekte bu konuyla alakasız. Yine de ihtiyacınız varsa, I = 1 ve I = 2 için çek koyabilirsiniz. İşte

+0

“int (ben)” tek şablon parametresi olmadığı için, “(ekstra) kısmi uzmanlık olmadan” demek istediğim buydu, ama başkaları da var. Gerçekten neye benzediğine dair küçük bir örnek için IEEE'ye bağlandım, yapı basit bir şekilde soruya dalmıştı. – Xeo

+0

Düzenlenmiş sürümü kontrol edebilir misiniz? Aslında 2. şablon versiyonunu ana sürüm olarak ekledim ve 1. versiyon 2. bir uzmanlık. Umarım yardımcı olur! – iammilind

3

gitmek:

http://ideone.com/AdEfl

Ve kod:

#include <iostream> 

template <int I> 
struct Traits 
{ 
    struct inner{}; 
}; 

template <> 
struct Traits<1> 
{ 
    struct inner{ 
    template<class T1> 
    struct impl{ 
     impl() { std::cout << "impl<T1>" << std::endl; } 
    }; 
    }; 
}; 

template <> 
struct Traits<2> 
{ 
    struct inner{ 
    template<class T1, class T2> 
    struct impl{ 
     impl() { std::cout << "impl<T1, T2>" << std::endl; } 
    }; 
    }; 
}; 

template<class T> 
struct Test{}; 

template<class T, class K> 
struct Foo{}; 

template<int I> 
struct arg{}; 

template< 
    template<class, class> class T, 
    class P1, int I 
> 
struct Test< T<P1, arg<I> > >{ 
    typedef typename Traits<I>::inner inner;  
}; 

template< 
    template<class, class> class T, 
    class P2, int I 
> 
struct Test< T<arg<I>, P2 > >{ 
    typedef typename Traits<I>::inner inner;  
}; 

// and a bunch of other partial specializations 

int main(){ 

    typename Test<Foo<int, arg<1> > >::inner::impl<int> b; 
    typename Test<Foo<int, arg<2> > >::inner::impl<int, double> c; 
} 

Açıklama: Temel olarak kısmi uzmanlaşma fikrinin bir uzantısı, ancak fark dahilinde uzmanlaşmış ziyade olmasıdır Test, yalnızca I üzerinde uzmanlaşabilen belirli bir sınıfa devredin.Bu şekilde, her bir Iiçin bir kez inner sürümlerini tanımlamanız yeterlidir. Daha sonra Test'un birden fazla uzmanlığı yeniden kullanılabilir. inner tutacağı, Test sınıfında daha kolay işlemek için typedef'u yapmakta kullanılır.

DÜZENLEME: http://ideone.com/QzgNP

+0

Aynı basitleştirilmiş kodu yayınladım, ancak sorgulayıcı şablonun "template " kadar basit olmayacağını söylüyor. – iammilind

+0

@iammilind, bunun bir uzantı olduğunu, kodun biraz farklı olduğunu söyledim, yukarıdaki "İhtiyaçlar" sınıfına "Ben" uzmanlığı verilir ve 'Test' sınıfı sizin cevabınızda OP'nin yapmaya istekli olmadığı her “Ben” için “Test” (ya da “X”) konusunda uzmanlaşmaktan bahsediyorum. – Nim

+0

doğru. Özür dilerim, bunu özledim. Araştırdığın için teşekkürler. – iammilind

0

Bir meta işlevini kullanabilirsiniz: burada şablon argümanları yanlış sayıda geçmek ne olur gösteren bir test niteliği taşıyor: için (burada boost::mpl::if_c inlined ama keyfi karmaşık olabilir) İstediğinizi seçin. Gerçi kurucular kullanabilmek için bazı iskele gerekir:

template <int I> 
class X { 
    template <typename T1> 
    class YforIeq1 { /* meat of the class */ }; 
    template <typename T1, typename T2> 
    class YforIeq2 { /* meat of the class */ }; 
public: 
    template <typename T1, typename T2=boost::none_t/*e.g.*/> 
    struct Y : boost::mpl::if_c<I==1,YforIeq1<T1>,YforIeq2<T1,T2> >::type { 
     typedef typename mpl::if_c<I==1,YforIeq1<T1>,YforIeq2<T1,T2> >::type YBase; 
     /* ctor forwarding: C++0x */ 
     using YBase::YBase; 
     /* ctor forwarding: C++03 (runs into perfect fwd'ing problem)*/ 
     Y() : YBase() {} 
     template <typename A1> 
     Y(const A1&a1) : YBase(a1) {} 
     template <typename A1, typename A2> 
     Y(const A1&a1, const A2&a2) : YBase(a1,a2) {} 
     // ... 
    }; 
}; 

hem YforIeqN ile ilgili bir sorun, her X için örneğinin oluşturulmasını varsa, o zaman boyunca (bir nullary meta işlevi olarak sarılarak bir şey deneyebilirsiniz mpl::apply yolunda) ve mpl::eval_if_c kullanın.

İlgili konular