Pregunta

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

interface IFoo
{
}


class Foo<T> where T : IFoo
{
}

class Bar : IFoo
{
}

class Simpson
{
}

class Program
{
    static void Main(string[] args)
    {
        Foo<Bar> a = new Foo<Bar>();
        Foo<Simpson> b = new Foo<Simpson>(); // error CS0309
    }
}

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


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

¿Fue útil?

Solución

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

Editar: Aumentar también tiene un alternativa propia.

Editar2:Parece Se han eliminado conceptos de C++ 0x..

Otros consejos

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

Por ejemplo,

#include <type_traits>

template<typename T>
class YourClass {

    YourClass() {
        // Compile-time check
        static_assert(std::is_base_of<BaseClass, T>::value, "type parameter of this class must derive from BaseClass");

        // ...
    }
}

"Implícitamente" es la respuesta correcta.Las plantillas crean efectivamente un escenario de "escritura de pato", debido a la forma en que están compiladas.Puede llamar a cualquier función que desee sobre un valor escrito en plantilla, y las únicas instancias que se aceptarán son aquellas para las cuales ese método está definido.Por ejemplo:

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

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

string s = "test";
vector<int> vec;
int i = 0;

compute_length(&s);
compute_length(&vec);

...pero no en un puntero a un tipo que no no declarar length():

compute_length(&i);

Este tercer ejemplo no se compilará.

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

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

class IFoo
{
public:
    typedef int IsDerivedFromIFoo;
};

template <typename T>
class Foo<T>
{
    typedef typename T::IsDerivedFromIFoo IFooGuard;
}

Verificar Aumentar

Biblioteca de verificación de conceptos de Boost (BCCL)

La biblioteca Concept Check permite agregar declaraciones explícitas y verificar conceptos al estilo de la propuesta de extensión del lenguaje C++.

Algo así como.Si realiza una transmisión estática a un IFoo*, será imposible crear una instancia de la plantilla a menos que la persona que llama pase una clase que pueda asignarse a un IFoo *.

Sólo implícitamente.
Cualquier método que utilice en un método que realmente se llama se impone en el parámetro de plantilla.

Puedes hacerlo.Crea la plantilla base.Que tenga sólo constructores privados.Luego cree especializaciones para cada caso que desee permitir (o haga lo contrario si la lista de no permitidos es mucho más pequeña que la lista de permitidos).

El compilador 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 t> class FOO { private: FOO(){}};

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

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

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

Mire el patrón CRTP (patrón de plantilla curiosamente recursivo).Está diseñado para ayudar a soportar la herencia estática.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top