2015-03-27 34 views
7

:Şablon meta kod ve özel üyeler

template <typename T> 
class Foo 
{ 
... 
public: 
    void DoSomething() 
    { 
     compile_time_if (T is ClassA) 
     { 
      m_T.DoThingOne(); 
      m_T.DoThingTwo(); 
     } 
     DoSomeFooPrivateThing(); 
     m_T.DoThingThree(); 
    } 
    T m_T; 
}; 

Bu durumda ben tüm geçerli TDoThingThree uygulamak biliyorum, ama sadece ClassADoThingOne ve DoThingTwo uygular. Bu ördek tipi bir şey değil, sadece ClassA için bu ekstra parçayı yapmak istiyorum ve bu yöntemleri diğer olası T s eklemek istemiyorum. Döküm yapamam, çünkü olası T s miras alınan türler değil. sınırlar

template <typename T> 
void Foo_DoSomething(T& t) 
{ 
    t.DoThingThree(); 
} 

template <> 
void Foo_DoSomething(ClassA& t) 
{ 
    t.DoThingOne(); 
    t.DoThingTwo(); 
    t.DoThingThree(); 
} 

template <typename T> 
class Foo 
{ 
... 
public: 
    void DoSomething() 
    { 
     Foo_DoSomething(m_T); 
    } 
... 
}; 

Ancak şimdi Foo özel üyelerine erişimi yok bu dış şablonu (DoSomeFooPrivateThing diyemezsin):

Ben bu karşılamak için harici yardımcı şablonunu kullanabilirsiniz biliyoruz işlevselliği ve dışarıdan, açıkça hoş olmayan dışa açık.

template <typename T> 
class Foo 
{ 
... 
public: 
    void DoSomething() 
    { 
     DoSomethingImpl(m_T); 
    } 
... 
private: 
    template <typename T2> 
    void DoSomethingImpl(T2& t) 
    { 
     DoSomeFooPrivateThing(); 
     t.DoThingThree(); 
    } 

    template <> 
    void DoSomethingImpl(ClassA& t) 
    { 
     t.DoThingOne(); 
     t.DoThingTwo(); 
     DoSomeFooPrivateThing(); 
     t.DoThingThree(); 
    } 
... 
}; 

Ama bu dış şablon tipi ve parametre çoğaltarak gerektirir: (. Arkadaş sadece kötü şeyler yapar harici yöntem Yapımı)

başka görünüşte-makul seçenek dahili olarak uygulamaktır. Bu muhtemelen kabul edilebilir, ama yine de biraz garip geliyor. Ne yazık ki, aslında derlemiyor (en azından GCC'de değil, sınıflardaki uzmanlıklara itiraz ediyor).

Bunu yapmanın daha iyi bir yolu var mı?

cevap

3

Bence son seçeneğin en iyisi.

yerine

template <> 
void DoSomethingImpl(ClassA& t) 
{ 
    t.DoThingOne(); 
    t.DoThingTwo(); 
    DoSomeFooPrivateThing(); 
    t.DoThingThree(); 
} 
sadece (burada template kullanımına gerek) kullanabilir

:

void DoSomethingImpl(ClassA& t) 
{ 
    t.DoThingOne(); 
    t.DoThingTwo(); 
    DoSomeFooPrivateThing(); 
    t.DoThingThree(); 
} 
+0

Evet, bu varyantı denediğimi ve işe yaradığını söylemek için soruyu güncellemek üzereydim. Teknik olarak belirsiz ama neyse ki açık aşırı yükler her zaman şablonlar üzerinde kazanıyor. Yine de, ilk parametrede şablon parametresinin hafifçe tahriş edici çoğaltılmasını gerektirir (çünkü bu, gerçekten bir belirsizlik yaratabilir) - ama bununla yaşayabilirim. – Miral

1

İlk çözüm: Eğer böyle yapabilirdi, dediğimiz gibi:

template <typename T> class Foo{ 

    public: 
    void doSomething(){ 
     doSomething(std::is_same<T,A>()); 
    } 
    private: 
    void doSomething(std::true_type){ 
     cout<<"A do"<<endl; 
    } 
    void doSomething(std::false_type){ 
     cout<<"any other do"<<endl; 
    } 
}; 

Second özüm: Foo şablon sınıfı yalnızca bir şablon parametresine sahip olduğundan, doğrudan bu şekilde açık bir uzmanlık yapabiliriz.

template <typename T> class Foo{ 

    public: 
    void doSomething(){ 
     cout<<"any other do..."<<endl; 
    } 

}; 

template<> void Foo<A>::doSomething(){ 
    cout<<"A do"<<endl; 

} 

Merkezlerinde çözüm: Belki değil iyi bir yol, böyle yapabilirdi, Bu şekilde (SFINAE) C++ 11 kullanın veya A tipi, derleyici oto ile aynıdır enable_if.When artırmak beklenen sınıfı seç.

#include <iostream> 
using namespace std; 
class A {}; 

template <typename T,typename Enable = void> 
class Foo 
{ 
public: 

    void DoSomething() 
    { 
     cout<<"anyother do"<<endl; 
    } 
private: 
    T m_T; 
}; 
template <typename T> class Foo<T, typename enable_if<is_same<T,A>::value>::type > 
{ 
public: 
    void DoSomething() 
    { 
     cout<<"A do"<<endl; 
    } 
private: 
    T m_T; 
}; 

Daha: İki Foo birçok aynı şeyleri varsa, böyle bunun için temel sınıfını yapabilir

:

template <typename T> class BaseFoo{ 
... 
}; 

ve bunun gibi BaseFoo türetilmiş iki şablon sınıfı:

template <typename T,typename Enable = void> 
class Foo:public BaseFoo<T>{...} 


    template <typename T> class Foo<T, typename enable_if 
<is_same<T,A>::value>::type >:public BaseFoo<T>{...} 
0

Son çözümüne alıştım, bu yüzden bana garip gelmiyor.
her zaman yapabileceğini İsterseniz

void DoSomethingImpl(T&t, std::true_type){...} 

ve

void DoSomethingImpl(T&t, std::false_type){...} 

ve sonra

DoSomethingImpl(m_T, std::is_same<T, ClassA>{}); 

Bu işlevsel olarak eşdeğer ama aynı zamanda verir daha karmaşık karar verme işlevi gerekiyorsa genişletilmiş

İlgili konular