Restricciones de plantillas C ++

En C #, podemos definir un tipo genérico que impone restricciones a los tipos que se pueden usar como parámetro genérico. El siguiente ejemplo ilustra el uso de restricciones genéricas:

interface IFoo { } class Foo where T : IFoo { } class Bar : IFoo { } class Simpson { } class Program { static void Main(string[] args) { Foo a = new Foo(); Foo b = new Foo(); // error CS0309 } } 

¿Hay alguna manera de imponer restricciones para los parámetros de plantilla en C ++?


C ++ 0x tiene soporte nativo para esto, pero estoy hablando de C ++ estándar actual.

Como alguien más ha mencionado, C ++ 0x está integrando esto en el lenguaje. Hasta entonces, recomendaría las sugerencias de Bjarne Stroustrup para las restricciones de la plantilla .

Editar: Boost también tiene una alternativa propia .

Edit2: Parece que los conceptos se han eliminado de C ++ 0x .

Si usa C ++ 11, puede usar static_assert con std::is_base_of para este propósito.

Por ejemplo,

 #include  template class YourClass { YourClass() { // Compile-time check static_assert(std::is_base_of::value, "type parameter of this class must derive from BaseClass"); // ... } } 

“Implícitamente” es la respuesta correcta. Las plantillas crean efectivamente un escenario de “tipado de pato”, debido a la forma en que se comstackn. Puede llamar a cualquier función que desee con un valor de tipo plantilla, y las únicas instancias que se aceptarán son aquellas para las que se define ese método. Por ejemplo:

 template  int compute_length(T *value) { return value->length(); } 

Podemos llamar a este método en un puntero a cualquier tipo que declare el método length() para devolver un int . Así que:

 string s = "test"; vector vec; int i = 0; compute_length(&s); compute_length(&vec); 

… pero no en un puntero a un tipo que no declara length() :

 compute_length(&i); 

Este tercer ejemplo no se comstackrá.

Esto funciona porque C ++ comstack una nueva versión de la función (o clase) templada para cada instanciación. A medida que realiza esa comstackción, realiza una sustitución directa, casi como una macro, de la instanciación de la plantilla en el código antes de la verificación de tipo. Si todo sigue funcionando con esa plantilla, entonces procede la comstackción y finalmente llegamos a un resultado. Si algo falla (como int* no declarando length() ), entonces obtenemos el temido error de tiempo de comstackción de seis páginas.

Puedes poner un tipo de guardia en IFoo que no haga nada, asegúrate de que esté allí en T en Foo:

 class IFoo { public: typedef int IsDerivedFromIFoo; }; template  class Foo { typedef typename T::IsDerivedFromIFoo IFooGuard; } 

Echa un vistazo a Boost

Boost Concept Check Library (BCCL)

La biblioteca Concept Check permite agregar una statement explícita y verificar conceptos en el estilo de la extensión de lenguaje C ++ propuesta .

Más o menos Si has static_cast a IFoo *, será imposible crear una instancia de la plantilla a menos que la persona que llama pase una clase que se puede asignar a un IFoo *.

Solo implícitamente.
Cualquier método que utilice en un método que realmente se llame se aplica al parámetro de la plantilla.

Puedes hacerlo. Crea la plantilla base. Haz que tenga solo constructores privados. A continuación, cree especializaciones para cada caso que desee permitir (o haga lo contrario si la lista no permitida es mucho más pequeña que la lista permitida).

El comstackdor no le permitirá crear instancias de las plantillas que usan la versión con constructores privados.

Este ejemplo solo permite la creación de instancias con int y float.

 template class FOO { private: FOO(){}}; template<> class FOO{public: FOO(){}}; template<> class FOO{public: FOO(){}}; 

No es una forma corta y elegante de hacerlo, pero es posible.

Mire el patrón CRTP (Curiously Recursive Template Pattern). Está diseñado para ayudar a soportar la herencia estática.