Respuesta corta: estás mezclando conceptos de tiempo de compilación anterior y tiempo de compilación que tienen similitudes en su propósito. Las interfaces (clases abstractas y toda la implementación del paradigma de orientación a objetos) se informan en tiempo de compilación . Los conceptos son la misma idea pero en el contexto de la programación genérica que en C ++ ocurre ANTES del tiempo de compilación . Todavía no tenemos esa última característica.
Pero déjame explicarte desde el principio.
Respuesta larga:
De hecho, los conceptos son solo información de lenguaje y "facilitan al programador" algo que ya está presente en el lenguaje, que podría llamarse "escritura de pato".
Cuando pasa un tipo a una función de plantilla, esa es una función genérica a partir de la cual el compilador generará código real (en línea) cuando se llama, ese tipo debe tener algunas propiedades (¿rasgos?) Que se utilizarán en el código de plantilla. Así que es la idea de escribir pato, PERO todo se genera y se hace en tiempo de compilación .
¿Qué sucede cuando el tipo no tiene las propiedades requeridas?
Bueno, el compilador sabrá que hay un problema solo una vez que el código generado a partir de la plantilla se compila y falla. Eso significa que el error que se generará será un error dentro del código de la plantilla, que se mostrará al programador como su error. Además, el error tendrá toneladas de información debido a las metainformaciones proporcionadas en caso de generación de código de plantilla, para saber de qué instancia de la plantilla estamos hablando.
Varios problemas con eso: primero, la mayoría de las veces, el código de plantilla es código de biblioteca y la mayoría de los programadores son usuarios de código de biblioteca, no escritores de código de biblioteca. Eso significa que este tipo de error críptico es realmente difícil de entender cuando no comprende cómo se escribe la biblioteca (no solo el diseño, cómo se implementa realmente). El segundo problema es que incluso cuando el programador escribió el código de la plantilla, las razones de la falla pueden ser oscuras porque el compilador podrá decir que hay un problema demasiado tarde: cuando se está compilando el código generado. Si el problema es relativo a las propiedades de tipo , debería comprobarlo incluso antes de generar el código.
Eso es lo que permiten los Conceptos (y están diseñados para): permitir que el programador (código genérico) especifique las propiedades de los tipos que se pasan como parámetros de plantilla y luego permitir que el compilador proporcione errores explícitos en caso de que los tipos proporcionados no cumplan con los requisitos requisitos
Una vez que la verificación es exitosa, el código se generará a partir de la plantilla y luego se compilará, ciertamente con éxito.
Todas las verificaciones de conceptos se realizan exclusivamente antes del tiempo de compilación . Comprueba los tipos ellos mismos, no los tipos de objetos . No hay ningún objeto antes del tiempo de compilación.
Ahora, sobre "interfaces".
Cuando crea un tipo base abstracto o virtual, permite que el código lo use para manipular objetos de los tipos secundarios sin conocer sus implementaciones reales. Para hacer cumplir esto, el tipo base expone miembros que son virtuales y podrían estar (o tienen que estar) sobrecargados por los tipos hijos.
Eso significa que el compilador puede verificar en el momento de la compilación que todos los objetos pasados a una función que requiere una referencia a la clase base deben ser 1. de uno de los tipos secundarios de la clase base, 2. ese tipo secundario debe tener implementaciones de funciones puras virtuales declaradas en clases base si las hay.
Entonces, en tiempo de compilación , el compilador verificará las interfaces de los tipos de objetos e informará si falta algo.
Es la misma idea que Conceptos, pero ocurre demasiado tarde , como se dice en la descripción del Concepto. Ocurre en tiempo de compilación. No estamos en código genérico (código de plantilla), estamos después de que se haya procesado y ya es demasiado tarde para verificar si los tipos cumplen con los requisitos genéricos, que no pueden ser expuestos por las clases base virtuales. De hecho, toda la implementación del paradigma de orientación a objetos en C ++ ni siquiera existe cuando se procesa el código de la plantilla. No hay objetos (todavía). Eso es
Las clases describen restricciones en los objetos que se utilizarán para verificar los requisitos para las funciones que manipulan esos objetos. Los conceptos describen restricciones sobre los tipos (incluidas las clases) que se utilizarán para verificar los requisitos de código genérico para generar código real a partir de esos tipos y la combinación de código genérico.
Entonces, nuevamente, es el mismo "control de cordura", pero en otra capa del lenguaje, eso es plantillas. Las plantillas son un lenguaje completo (turing completo) que permite meta-programación, tipos de programación incluso antes de que aparezcan en el código compilado. Es un poco como crear un script para el compilador. Digamos que puede escribirlo, las clases son solo valores manipulados por el script. Actualmente, no hay forma de verificar las restricciones en estos valores que no sea bloquear el script de una manera no obvia. Los conceptos son solo eso: proporcionar tipeo en estos valores (que en el código generado son tipos). No estoy seguro de que esté claro ...
Otra diferencia realmente importante entre las clases base virtuales y los Conceptos es que la primera fuerza una fuerte relación entre los tipos, haciéndolos "atados por la sangre". Mientras que la metaprogramación de plantillas permite "escribir pato" que los Conceptos simplemente permiten aclarar los requisitos.
La respuesta simple a prácticamente todas sus preguntas es: "Porque los compiladores de C ++ apestan". Seriamente. Se basan en la tecnología de la Unidad de Traducción de C, que efectivamente prohíbe muchas cosas útiles, y las implementaciones de plantillas existentes son horriblemente lentas. Los conceptos no se cortaron por ninguna razón conceptual: se cortaron porque no había una implementación confiable, ConceptGCC fue extremadamente lento y la especificación de conceptos tomó un tiempo absurdamente largo. Herb Sutter declaró que se necesitaba más espacio para especificar los conceptos utilizados en la biblioteca estándar que para especificar la totalidad de las plantillas.
Podría decirse que entre SFINAE
decltype
ystatic_assert
, en su mayoría, son implementables como lo es ahora de todos modos.fuente
Según tengo entendido, las Interfaces y los Conceptos tienen propósitos similares en diferentes partes del lenguaje C ++.
Como se menciona en la respuesta a la pregunta original: la implementación de una interfaz es decidida por el implementador de una clase en tiempo de diseño. Una vez que se ha publicado una clase, puede admitir solo aquellas interfaces de las que se derivó en tiempo de diseño.
Dos interfaces distintas con exactamente las mismas funciones miembro y semántica (es decir, el mismo concepto) seguirán siendo dos interfaces distintas. Si desea admitir la semántica de ambas interfaces, es posible que deba implementar el soporte dos veces.
Ese es el problema que la Programación Genérica intenta solucionar. En la programación genérica de C ++, el tipo pasado a una plantilla simplemente necesita admitir la interfaz (sin mayúscula, en el sentido de la "interfaz de programación" de un tipo) que utiliza la plantilla. Las dos interfaces distintas con las mismas funciones miembro coincidirán, y deberá escribir el código solo una vez. Además, funcionará cualquier tipo (incluso sin interfaces explícitas) que admitan la misma interfaz.
Esto lleva a un segundo problema: ¿qué sucede si tiene dos tipos con interfaces superpuestas pero con semántica diferente ? La programación genérica no podrá notar la diferencia y todo se compilará bien, pero el resultado en tiempo de ejecución será sorprendente y probablemente incorrecto.
Ahí es donde entran los conceptos. Si simplifica demasiado, puede considerar un concepto como la versión genérica (plantilla) de una interfaz. Debe implementarse solo una vez para aplicarse a una gran cantidad de tipos potenciales que pueden "derivarse" del Concepto. Un concepto es una interfaz semántica predeterminada de un tipo (clase) que no se limita únicamente a ese tipo. Es diferente a una interfaz en que dos tipos muy diferentes (para el compilador genérico) todavía pueden tener el mismo concepto, sin tener que recurrir a interfaces de clase base limitantes o interfaces de clase base que no tengan una semántica real visible para el compilador de sus propio, pero solo se utilizan para la distinción de tipo.
fuente