Modèle de classe C ++ de classe de base spécifique

Disons que j’ai les classes:

class Base{}; class A: public Base{ int i; }; class B:public Base{ bool b; }; 

Et maintenant je veux définir une classe basée sur un modèle:

 template  class BasePair{ T1 first; T2 second; }; 

Mais je veux le définir de telle sorte que seuls les décendants de la classe Base puissent être utilisés comme parameters de template.

Comment puis je faire ça?

Plus exactement:

 class B {}; class D1 : public B {}; class D2 : public B {}; class U {}; template  class P { X x; Y y; public: P() { (void)static_cast((X*)0); (void)static_cast((Y*)0); } }; int main() { P ok; P nok; //error } 

C ++ 11 introduit

 template  class BasePair{ static_assert(std::is_base_of::value, "T1 must derive from Base"); static_assert(std::is_base_of::value, "T2 must derive from Base"); T1 first; T2 second; }; 

C ++ ne permet pas encore cela directement. Vous pouvez le réaliser indirectement en utilisant un STATIC_ASSERT et en STATIC_ASSERT vérification dans la classe:

 template < typename T1, typename T2 > class BasePair{ BOOST_STATIC_ASSERT(boost::is_base_of); BOOST_STATIC_ASSERT(boost::is_base_of); T1 first; T2 second; }; 

C’était une bonne question! En recherchant ceci via ce lien , je suis arrivé avec ce qui suit, ce qui n’est certes pas très différent de la solution fournie ici. Apprenez quelque chose tous les jours … vérifiez!

 #include  #include  #include  using namespace std; template class IsDerivedFrom { class No { }; class Yes { No no[3]; }; static Yes Test(B*); // declared, but not defined static No Test(...); // declared, but not defined public: enum { IsDerived = sizeof(Test(static_cast(0))) == sizeof(Yes) }; }; class Base { public: virtual ~Base() {}; }; class A : public Base { int i; }; class B : public Base { bool b; }; class C { ssortingng z; }; template  class BasePair { public: BasePair(T1 first, T2 second) :m_first(first), m_second(second) { typedef IsDerivedFrom testFirst; typedef IsDerivedFrom testSecond; // Comstack time check do... BOOST_STATIC_ASSERT(testFirst::IsDerived == true); BOOST_STATIC_ASSERT(testSecond::IsDerived == true); // For runtime check do.. if (!testFirst::IsDerived) cout << "\tFirst is NOT Derived!\n"; if (!testSecond::IsDerived) cout << "\tSecond is NOT derived!\n"; } private: T1 m_first; T2 m_second; }; int main(int argc, char *argv[]) { A a; B b; C c; cout << "Creating GOOD pair\n"; BasePair good(a, b); cout << "Creating BAD pair\n"; BasePair bad(c, b); return 1; } 
 class B { }; class D : public B { }; class U { }; template  class P { X x; Y y; public: P() { (void)static_cast((Y*)0); } }; 

Tout d’abord, corrigez la déclaration

 template < class T1, class T2 > class BasePair{ T1 first; T2 second; }; 

Ensuite, vous pouvez déclarer dans une classe de base une fonction privée Foo (); et dire à la classe de base d’avoir BasePair comme ami; alors dans le constructeur ami il suffit d’appeler cette fonction. De cette façon, vous obtiendrez une erreur de compilation lorsque quelqu’un essaiera d’utiliser d’autres classes comme parameters de modèle.

Dans la réponse suggérée par unknown (yahoo), il n’est pas nécessaire d’avoir les variables de type X et Y comme membres. Ces lignes sont suffisantes dans le constructeur:

 static_cast((X*)0); static_cast((Y*)0);