¿Cómo asegurar que el parámetro de plantilla sea un subtipo del tipo deseado?

Tengo una clase de plantilla, lo que quiero hacer es lo siguiente

  1. Asegúrese de que un objeto se crea una instancia solo si el parámetro de plantilla pasado es un subtipo del tipo deseado
  2. Comunica al usuario del código por adelantado qué es lo que el parámetro de la plantilla debe satisfacer

(1) es una especie de cuidado automático en el sentido de que si el parámetro de plantilla aprobado no admite alguna característica que la clase utiliza, el código no se comstackrá. Pero este error puede detectarse bastante tarde. Quiero que los cheques sean lo más temprano posible. Lo que también quiero lograr es que debe ser obvio que el parámetro de la plantilla que se pasa debe derivarse de un tipo de base que proporciono.

Primero, ¿esto está equivocado? y si no, ¿cómo voy a hacer esto? (la forma más simple, por favor, C ++ todavía es nuevo para mí)

Gracias stackoverflow, realmente has acelerado mi tasa de aprendizaje de C ++.

Dado un tipo completo de MyBase , lo siguiente arrojará un error de tiempo de comstackción si T no se deriva de MyBase :

 #include  #include  template class Foo { BOOST_STATIC_ASSERT_MSG( (boost::is_base_of::value), "T must be a descendant of MyBase" ); // Foo implementation as normal }; 

Si está utilizando un comstackdor C ++ 03 con TR1, puede usar std::tr1::is_base_of lugar de boost::is_base_of ; si está utilizando un comstackdor de C ++ 11, puede usar std::is_base_of lugar de boost::is_base_of y la palabra clave static_assert lugar de la macro BOOST_STATIC_ASSERT_MSG :

 #include  template class Foo { static_assert( std::is_base_of::value, "T must be a descendant of MyBase" ); // Foo implementation as normal }; 

Nb esto arrojará true_type para los tipos derivados de manera privada y ambigua, por lo que esto es insuficiente si lo que realmente necesita es tratar a T como un MyBase (en la mayoría de los contextos).

Enlaces a documentos:
Boost . StaticAssert
Boost . TypeTraits

Desde el “Diseño moderno en C ++”, capítulo 2.7 (“Detección de convertibilidad y herencia en tiempo de comstackción”): puede usar un truco de sizeof :

 typedef char Small; class Big { char dummy[2]; }; Small Test(Base1); Big Test(...); const bool isSubclassOfBase1 = sizeof(Test(Derived1())) == sizeof(Small); 

Explota el hecho de que sizeof(...) puede averiguar el tipo al que evalúa la expresión y dado que los valores de retorno tienen diferentes tamaños, la comprobación == evalúa como verdadera o falsa. Si Derived1 es de hecho la base de Base1, Small Test(Base1); se elige sobrecarga y isSubclassOfBase1 será verdadero.

A partir de eso, puede encapsular un cheque y hacer una aserción estática para hacer que falle en el momento de la comstackción:

 #include  class A {}; class B: public A {}; class C {}; template struct SubclassCheck { typedef char Yes; class No { char dummy[2]; }; static Yes Test(Base); static No Test(...); enum { Value = (sizeof(Test(*(Derived*)NULL)) == sizeof(Yes)) }; }; #define CHECK_DERIVES(b,d)\ BOOST_STATIC_ASSERT((SubclassCheck::Value)); int main() { CHECK_DERIVES(A, B); // CHECK_DERIVES(A, C); // fails } 

Puede utilizar cualquier otra implementación de aserción estática, no necesariamente la de Boost.

Sí, esto se soluciona automáticamente porque si el parámetro no admite las cosas que haces con él, se producirá un error de comstackción. Comprobar manualmente si un tipo es un subtipo de otro tipo solo puede (AFAIK) hacerse en tiempo de ejecución, que es mucho más tarde que el tiempo de comstackción. No sé a qué te refieres con que ese error se haya detectado tarde, el tiempo de comstackción es tan pronto como sea posible. Además, si todos verificaran el tipo de sus parámetros de plantilla, el STL no podría funcionar con punteros así como con iteradores reales basados ​​en clases, y no sería tan flexible.

En cuanto a dejar que su usuario conozca los requisitos, simplemente bríndelos en la documentación.