Disons que j'ai les cours:
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 des modèles:
template < typename T1, typename T2 >
class BasePair{
T1 first;
T2 second;
};
Mais je veux le définir de telle sorte que seuls les descendants de la classe Base puissent être utilisés comme paramètres de modèle.
Comment puis je faire ça?
Plus exactement:
class B {};
class D1 : public B {};
class D2 : public B {};
class U {};
template <class X, class Y> class P {
X x;
Y y;
public:
P() {
(void)static_cast<B*>((X*)0);
(void)static_cast<B*>((Y*)0);
}
};
int main() {
P<D1, D2> ok;
P<U, U> nok; //error
}
C++ 11 introduit <type_traits>
template <typename T1, typename T2>
class BasePair{
static_assert(std::is_base_of<Base, T1>::value, "T1 must derive from Base");
static_assert(std::is_base_of<Base, T2>::value, "T2 must derive from Base");
T1 first;
T2 second;
};
C++ ne le permet pas encore directement. Vous pouvez le réaliser indirectement en utilisant un STATIC_ASSERT
et vérification de type à l'intérieur de la classe:
template < typename T1, typename T2 >
class BasePair{
BOOST_STATIC_ASSERT(boost::is_base_of<Base, T1>);
BOOST_STATIC_ASSERT(boost::is_base_of<Base, T2>);
T1 first;
T2 second;
};
C'était une excellente question! En recherchant ceci via ceci lien , j'ai trouvé ce qui suit, qui n'est certes pas très différent de la solution fournie là-bas. Apprenez quelque chose tous les jours ... vérifiez!
#include <iostream>
#include <string>
#include <boost/static_assert.hpp>
using namespace std;
template<typename D, typename B>
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<D*>(0))) == sizeof(Yes) };
};
class Base
{
public:
virtual ~Base() {};
};
class A : public Base
{
int i;
};
class B : public Base
{
bool b;
};
class C
{
string z;
};
template <class T1, class T2>
class BasePair
{
public:
BasePair(T1 first, T2 second)
:m_first(first),
m_second(second)
{
typedef IsDerivedFrom<T1, Base> testFirst;
typedef IsDerivedFrom<T2, Base> testSecond;
// Compile 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<A, B> good(a, b);
cout << "Creating BAD pair\n";
BasePair<C, B> bad(c, b);
return 1;
}
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 Base d'avoir BasePair comme ami; puis dans ami constructeur, il vous suffit d'appeler cette fonction. De cette façon, vous obtiendrez une erreur de compilation lorsque quelqu'un essaie d'utiliser d'autres classes comme paramètres de modèle.
class B
{
};
class D : public B
{
};
class U
{
};
template <class X, class Y> class P
{
X x;
Y y;
public:
P()
{
(void)static_cast<X*>((Y*)0);
}
};
Dans la réponse suggérée par unknown (yahoo), il n'est pas nécessaire d'avoir réellement les variables de type X et Y comme membres. Ces lignes sont suffisantes dans le constructeur:
static_cast<B*>((X*)0);
static_cast<B*>((Y*)0);