geeksforgeeks - preprocessor c++
Plantilla de clase C++ de clase base especĂfica (7)
Digamos que tengo las clases:
class Base{};
class A: public Base{
int i;
};
class B:public Base{
bool b;
};
Y ahora quiero definir una clase con plantilla:
template < typename T1, typename T2 >
class BasePair{
T1 first;
T2 second;
};
Pero quiero definirlo de forma que solo los descendientes de la clase Base puedan usarse como parámetros de plantilla.
¿Cómo puedo hacer eso?
¡Esta fue una gran pregunta! Al investigar esto a través de este link , se me ocurrió lo siguiente, que ciertamente no es muy diferente de la solución proporcionada allí. Aprende algo todos los días ... ¡mira!
#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;
}
C ++ 11 introduce <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 ++ todavía no permite esto directamente. Puedes realizarlo indirectamente usando STATIC_ASSERT
y escribir checking dentro de la clase:
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;
};
En la respuesta sugerida por unknown (yahoo), no es necesario tener realmente las variables de tipo X e Y como miembros. Estas líneas son suficientes en el constructor:
static_cast<B*>((X*)0);
static_cast<B*>((Y*)0);
Más exactamente:
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
}
Primero, arregle la declaración
template < class T1, class T2 >
class BasePair{
T1 first;
T2 second;
};
Entonces, puede declarar en una clase base alguna función privada Foo (); y decirle a la clase Base que tenga a BasePair como amigo; luego en amigo constructor solo tienes que llamar a esta función. De esta forma obtendrá un error de tiempo de compilación cuando alguien intente usar otras clases como parámetros de plantilla.
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);
}
};