En programación genérica , un concepto es una descripción de las operaciones admitidas en un tipo , incluidas la sintaxis y la semántica. De esta manera, los conceptos se relacionan con tipos abstractos , pero no requieren una relación de subtipo.
El término se utilizaba ya en 1998 para STL , [1] ya que esta era una de las primeras bibliotecas que utilizaba plantillas de forma extensiva. El concepto del término (y su popularización) se le atribuye a Alexander Stepanov , [2] [3] el diseñador principal de STL.
En el estándar C++ 1998, el término Concepto se introdujo para nombrar simplemente una descripción simple de los requisitos para un tipo particular, generalmente un parámetro de plantilla. No se codificó en el lenguaje de manera explícita; el concepto se expresó solo por las operaciones que se intentaban en los objetos de ese tipo y lo que se esperaba que funcionara (es decir, que se compilara correctamente). Hubo una propuesta para agregar conceptos como una característica explícita del lenguaje en C++11 , aunque se rechazó por "no estar lista". C++20 finalmente aceptó el diseño refinado de concepto.
Como los genéricos en Java y C# tienen algunas similitudes con las plantillas de C++ , el papel de los conceptos lo desempeñan las interfaces . Sin embargo, existe una diferencia importante entre conceptos e interfaces: cuando se requiere un parámetro de plantilla para implementar una interfaz en particular, el tipo coincidente solo puede ser una clase que implemente (explícitamente) esa interfaz. Los conceptos aportan más flexibilidad porque se pueden satisfacer de dos maneras:
Pero el lenguaje C# tiene varias construcciones donde el tipo utilizado no necesita implementar explícitamente una interfaz definida, solo se requiere que coincida con el patrón respectivo (sin embargo, estos patrones no se llaman conceptos ). Por ejemplo, la foreach
declaración de iteración permite que el objeto iterado sea de cualquier tipo, siempre que implemente un GetEnumerator
método apropiado. [4] (Compare con la using
declaración que requiere que el recurso implemente la System.IDisposable
interfaz. [5] )
El lenguaje de programación Nim implementa conceptos como una serie de predicados booleanos arbitrarios en tiempo de compilación. [6]
Otro lenguaje que implementa algo muy similar a los conceptos es Haskell , donde la característica se llama clases de tipos .
El concepto de ordenación total describe la semántica del <
operador. Un tipo está totalmente ordenado cuando <
es un predicado binario y satisface las siguientes propiedades: [7] [8]
!(a < a)
para cualquier valor a
.a < b
y b < c
entonces a < c
.a < b
entonces !(b < a)
.a != b
entonces a < b
o b < a
.Muchos algoritmos dependen de estas propiedades para funcionar correctamente. Por ejemplo, la min
función se puede definir de forma segura en tipos totalmente ordenados:
#include <conceptos> plantilla < typename T > requiere std :: totally_ordered < T > T min ( T a , T b ) { // < está definido. if ( b < a ) { return b ; } else { // !(b < a) implica a == b o a < b return a ; } }
Si un tipo I
satisface el concepto de Iterador Trivial en C++, y i
es del tipo I
, las siguientes son expresiones válidas con la semántica correspondiente: [9]
I i
construcción predeterminada.*i
Debe ser convertible a algún tipo T
.i->m
es válido si (*i).m
es.