Creo que los conceptos son una especie de metainterfaz. Categorizan tipos según sus habilidades. La próxima versión de C++ proporciona conceptos nativos. No lo había entendido hasta que encontré los conceptos de C++ 1x y cómo permiten unir tipos diferentes pero no relacionados. Imagine que tiene una interfaz Range
. Puedes modelar eso de dos maneras. Uno de ellos es una relación subtipo:
class Range {
virtual Iterator * begin() = 0;
virtual Iterator * end() = 0;
virtual size_t size() = 0;
};
Por supuesto, cada clase que deriva de que implementa la interfaz rango y se puede utilizar con sus funciones. Pero ahora ves que es limitado. ¿Qué hay de una matriz? ¡Es un rango también!
T t[N];
begin() => t
end() => t + size()
size() => N
Lamentablemente, no puede derivar una matriz de esa clase Range que implementa esa interfaz.Necesita un método adicional (sobrecarga). ¿Y qué hay de los contenedores de terceros? Un usuario de su biblioteca puede querer usar sus contenedores junto con sus funciones. Pero él no puede cambiar la definición de sus contenedores. Aquí, los conceptos entran en juego:
auto concept Range<typename T> {
typename iterator;
iterator T::begin();
iterator T::end();
size_t T::size();
}
Ahora, usted dice algo sobre las operaciones compatibles de algún tipo que puede ser cumplida si T
tiene las funciones miembro apropiadas. En tu biblioteca, escribirías la función genérica. Esto le permite aceptar cualquier tipo tanto tiempo como que soporta las operaciones necesarias:
template<Range R>
void assign(R const& r) {
... iterate from r.begin() to r.end().
}
Es un gran tipo de sustitución . Cualquier tipo de se ajustará a la factura que se adhiere al concepto, y no solo a los tipos que implementan activamente alguna interfaz. El siguiente estándar de C++ va más allá: define un concepto Container
que se ajustará a matrices simples (por algo llamado mapa conceptual que define cómo un tipo se ajusta a algún concepto) y otro, contenedores estándar existentes.
La razón por la que menciono esto es porque tengo un contenedor con plantilla, donde los contenedores en sí tienen una relación jerárquica. Me gustaría escribir algoritmos que usen estos contenedores sin importar qué contenedor específico es. Además, algunos algoritmos se beneficiarían de saber que el tipo de plantilla cumple ciertos conceptos (comparable, por ejemplo).
Puede hacer ambas cosas con las plantillas. Puede seguir teniendo su relación jerárquica para compartir código y luego escribir los algoritmos de forma genérica. Por ejemplo, para comunicar que su contenedor es comparable. Eso es como norma de acceso aleatorio/avance/salida/entrada categorías iterador se implementan:
// tag types for the comparator cagetory
struct not_comparable { };
struct basic_comparable : not_comparable { };
template<typename T>
class MyVector : public BasicContainer<T> {
typedef basic_comparable comparator_kind;
};
/* Container concept */
T::comparator_kind: comparator category
Es una manera sencilla razonable para hacerlo, en realidad. Ahora puede llamar a una función y reenviará a la implementación correcta.
template<typename Container>
void takesAdvantage(Container const& c) {
takesAdvantageOfCompare(c, typename Container::comparator_kind());
}
// implementation for basic_comparable containers
template<typename Container>
void takesAdvantage(Container const& c, basic_comparable) {
...
}
// implementation for not_comparable containers
template<typename Container>
void takesAdvantage(Container const& c, not_comparable) {
...
}
En realidad, existen diferentes técnicas que se pueden utilizar para implementar eso. Otra forma es usar boost::enable_if
para habilitar o deshabilitar diferentes implementaciones cada vez.
C++ 1x? ¿Significa eso que dejaron de publicar el nuevo estándar en esta década o están hablando del futuro desarrollo de C++? – jpalecek
http://www.research.att.com/~bs/C++0xFAQ.html#concepts – jmucchiello
jpalecek, quieren lanzarlo en 2010. Tengo la costumbre de llamarlo C++ 1x :) –