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 los conceptos no requieren una relación de subtipo.
El término ya se utilizaba en 1998 para STL , [1] ya que fue una de las primeras bibliotecas que utilizó plantillas de forma extensiva. El término concepto (y su popularización) se atribuye a Alexander Stepanov , [2] [3] el diseñador principal del 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, que generalmente es un parámetro de plantilla. No estaba codificado explícitamente en el lenguaje; el concepto se expresaba únicamente mediante las operaciones que se intentaban en 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 fue rechazada por "no estar lista". C++20 finalmente aceptó el diseño refinado del 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 pueden satisfacerse de dos maneras:
Pero el lenguaje C# tiene varias construcciones en las que 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 denominan 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] (Compárese 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 orden 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)
por 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 < nombre de tipo T > requiere std :: totalmente_ordenado < T > T min ( T a , T b ) { // < está definido. si ( b < a ) { return b ; } else { // !(b < a) implica a == b o a < b return a ; } }
Si un tipo I
satisface el concepto Trivial Iterator en C++ y i
es de tipo I
, las siguientes son expresiones válidas con la semántica correspondiente: [9]
I i
construcción por defecto.*i
debe ser convertible a algún tipo T
.i->m
es válido si (*i).m
lo es.