自c++11以来,c ++标准委员会的目标是每 3 年批准一个新标准。迄今为止,情况一直如此,我们有以下标准:
标准化分为四个工作组:
- Nucleus(核心):维护新提案的语言和标准化。
- Evolution:开发语言的新功能。
- 图书馆:标准图书馆的维护和新提案的标准化。
- 库演变:为标准库开发新功能。
2019 年 7 月,C++20 标准被认为是封闭的。这意味着不能添加新功能(尽管如果检测到问题可以删除一些功能),并且正在审查批准的功能以进行可能的改进或较小的更正。
在最后一次会议上,考虑到 Contracts 2提案(技术文档P0542R4)将不会并入 C++20 并延迟到 C++23。
我们将列出 C++20 将包含的一些主要特性。
1由于一些奇怪的疏忽,我写了两个关于 C++17 的线程。
2根据维基百科,合同是:
按合同设计是一种由Eiffel编程语言推广的应用程序和组件的设计和实现方法。它包括将设计元素视为类似于商业合同的关系的参与者。因此,可以设计组件,假设将满足某些输入条件(前置条件),同时必须保证某些输出条件(后置条件)以及类不变性(尽管由零件)。
C++ 契约将遵循属性语法(在 C++11 中添加):
[[contrato modificador: expresión-condicional]]
合约已移至 C++23,以下内容可能会发生变化: 可用的合约有:
expects
: 类型合同expects
是先决条件。指示函数期望从其参数中得到什么,并且该合约预计将在整个函数调用中保持。ensures
:类型合同ensures
是一个后置条件。指示传递给函数(或从函数返回)的对象在调用结束时应具有的状态。asert
: 类型契约assert
是一个断言。表示在合同出现的地方预期会满足的条件。
当合约未履行时,将使用以下签名进行函数调用:
void(const std::contract_violation &);
该对象std::contract_violation
将包含有关违约的信息,例如(文件、行、功能)被违反的位置。
修饰符可以应用于合约,修饰符将影响如何生成带有合约的代码以及是否在运行时检查合约。可用的修饰符有:
axiom
:本合同条件的验证预计没有成本,在执行时不进行评估。default
: 预计本合同条件的验证费用不高。audit
: 预计本合同条款的验证费用很高。
将在编译时验证的合约包含将被编译的代码,您可以指定要编译每个翻译单元的级别,结果行为将是:
- 默认值:检查(编译)标记为
default
(考虑没有修饰符的合同)的合同default
。 - 审计:验证(编译)标记为
audit
和的合同default
。
核。
概念。
概念是对 C++ 模板系统的增强,它们是一种特殊类型的编译时可评估函数,必须返回true才能认为概念为真。它的作用是控制模板的参数必须满足的特性。但它们的功能不仅限于模板的范围,它们还可以在其他上下文中使用。
概念是期待已久的 C++ 功能,它已经酝酿了 10 年(由于时间不足,它被排除在 C++11 之外,由于不完整而被排除在 C++14 之外,并且由于以下原因被排除在 C++17 之外缺乏共识)。
例子
我们可以定义一个概念如下:
a + b
如果表达式是可能的并且它的类型是,则满足前面的概念tipo_t
,那么我们可以使用该概念作为参数:并且该函数
suma
将只接受满足该概念的类型es_sumable
。它也可以用作变量:变量
resultado
必须匹配es_sumable
,否则代码将无法编译。最后,可能需要一个模板来满足一个或多个概念:在前面的函数中,模板参数
T
必须是一个32位的整数,如果不是,则会显示一个清晰简洁的错误:聚合中按名称的初始化程序 (DT P0329R0 )
允许在聚合类型的对象的初始化中指定名称的建议,正如 C 中已经允许的那样(自 C99 起)。
例子
假设我们有以下对象:
从 C++20 开始,以下初始化是正确的:
必须考虑到与 C99 相比的某些差异:
所有成员都必须初始化:
成员必须按定义顺序排列:
成员不得重复:
不允许编队初始化:
不允许嵌套初始化:
Lambdas模板 (DT P0428R2 )
从 C++14 开始,该语言允许Generic Lambda;但是虽然它们使 C++ Lambda 更有用,但通用 Lambda 并没有提供预期的灵活性,以至于在某些情况下使用模板函数而不是通用 Lambda 仍然更有用。本白皮书为 Lambdas 提出了以下新语法:
也就是说,尖括号 (
<
和>
) 被添加到 Lambda 以处理模板参数。例子
仅适用于
std::vector
通用版本的 Lambda:模板版本:
调用传递类型的静态函数并访问嵌套类型的 Lambda 通用版本:
模板版本:
三路比较(白皮书P0515R3)。
该提议以化名“宇宙飞船操作员”而闻名,因为提议的操作员 (
operator <=>
) 与 Tie-Fighter 相似:该提案建议在语言中添加一个新的运算符来执行对象之间的比较,从而能够获得三种不同的结果。对于三向比较,
a <=> b
将获得以下结果:a
值b
。a
和相等,则值为零b
。a
则大于零的值b
。三路比较将减少允许数据严格排序所需的代码量,这需要进行几次比较,这些比较通常基于前面的比较来实现以节省代码:
该提案建议允许编译器默认生成三路比较,这样做将在运算符的运算符之间递归地执行成员到成员的三路比较。
例子
上面代码中对象的三路比较(由编译器生成):
返回类型将是
auto
因为返回类型取决于编译器,它必须遵循的唯一限制是它可以与零进行比较(大于、小于或等于零)。for
带初始化程序的范围(技术文档P0614R1)for
在 C++11 中,使用以下语法添加了范围循环:for
它允许您创建更易于理解和维护的代码,但由于不允许使用初始化程序而缺乏传统循环的灵活性。for
建议是用初始化器放宽范围循环:例子
我们得到一个临时对象,我们从中迭代它的一个内部属性:
默认可构造和可映射无状态 Lambda (DT P0624R2 )
没有捕获的 lambda 被称为“没有状态的 Lambda ”,这种类型的 lambda 可以隐式转换为函数指针:
Pero en algunas situaciones no se comportan como punteros a función. Los punteros a función son copiables, asignables y construibles mientras que las lambdas sin estado no lo son.
Ejemplo
Esta propuesta hace que las lambda sin estado se comporten como punteros a función:
Permitir la expansión de paquetes de parámetros en la captura de lambdas (DT P0780R0)
En una lambda se pueden capturar los parámetros por copia:
Pero el estándar previo a C++20 prohíbe explícitamente expandir paquetes de parámetros en las capturas.
Ejemplo
C++20 levanta esta prohibición:
Literales de cadena de caracteres como parámetros no-tipo en plantillas (DT P0424R2)
El estándar previo a C++20 establece explícitamente que los literales de cadena de caracteres no pueden ser usados como parámetros de plantilla:
El motivo de esta limitación es que dos literales de texto iguales (como en el ejemplo anterior) no tienen garantías de ser el mismo literal (se almacenan como punteros) y en consecuencia no hay manera de saber si dos funciones con el mismo literal de texto son la misma. En C++20 se permite la verificación del parámetro literal de texto en tiempo de compilación pudiendo comprobar si dos literales de texto tienen el mismo contenido, esto permite que los literales de texto puedan ser usados como parámetros no-tipo en plantillas.
Macros de verificación de funcionalidades (DT P0941R1)
Si el compilador dispone de una funcionalidad determinada, ésta podrá ser verificada usando la macro
__has_cpp_attribute
. La macro recibirá un único parámetro que será un identificador asociado a una funcionalidad determinada.Ejemplo
Si el compilador dispone del bucle
for
de rango (C++11) lo usamos, usamos el bucle tradicional en caso contrario:###Explícito condicional
explicit(bool)
(documento técnico P0892R2). En el estándar C++11 se permitió controlar las conversiones implícitas al construir o convertir objetos al permitir marcar como explícitos los constructores u operadores. En C++20 se amplía esta funcionalidad pudiendo pasar un parámetro al especificadorexplicit
para hacer que éste se aplique condicionalmente.Ejemplo
El objeto
O
tiene un constructor explícito cuando el tipo usado para construirlo sea de mayor tamaño que el tipo almacenado, constructor implícito en caso contrario:La palabra clave
explicit
esperará una expresión convertible a booleano a partir de C++20, así que habrá que corregir algunas líneas de código:Permitir que las llamadas a funciones virtuales sean
constexpr
(DT P1064R0)Las llamadas a funciones virtuales están prohibidas en expresiones constantes en estándares previos a C++20.
Ejemplo
El compilador conoce los tipos implicados en algunas llamadas virtuales y podría resolver la llamada en tiempo de compilación.
Funciones Inmediatas (DT P1073R2)
A partir de C++11 se puede usar la palabra clave
constexpr
para marcar valores o funciones que podrían ser válidas dentro de una expresión constante (expresión calculada en tiempo de compilación). Las funciones marcadas comoconstexpr
pueden también ser llamadas en tiempo de ejecución.Esta propuesta añade la palabra clave
consteval
para marcar valores o funciones que obligatoriamente deben ser evaluadas en tiempo de compilación y producir un error en caso contrario.Las funciones
consteval
reciben el nombre de función inmediata porque la función no se compila para ser ejecutada si no que se evalúa en tiempo de compilación y se sustituye su llamada por el resultado de la evaluación, una función inmediata no tiene por qué aparecer en el binario compilado.Ejemplo
Las funciones inmediatas provocan un error de compilación si no se pueden calcular en tiempo de compilación:
constinit
(DT P1143R2)El lenguaje C++ no especifica el orden en que las variables estáticas deben ser inicializadas, dejando esta decisión en manos de los compiladores. Esto provoca que las variables estáticas con inicializadores dinámicos provoquen errores difíciles de rastrear cuando unas dependen de otras (esto se conoce como Static Initialization Order Fiasco). Las variables con inicializadores constantes evitan este problema, ya que pueden inicializarse en tiempo de compilación y se pueden usar de manera segura para inicializar otras variables.
Para garantizar que una variable se inicializa en tiempo de compilación, se debe obligar al compilador a que la inicialización sea constante, para ello se puede marcar una con
constinit
:Ejemplo
Tenemos una función (
valor_dinamico
) que calcula un valor en tiempo de ejecución y otra (misterio
) que podría ser evaluada en tiempo de compilación o en tiempo de ejecución:Si
misterio
no puede ser evaluada en tiempo de compilación, la expresión marcada conconstinit
falla.using
enumerado (DT P1099r5)En C++11 se añadieron al lenguaje los enumerados-clase:
Este nuevo tipo de enumerado no exporta sus símbolos al ámbito superior:
Ejemplo
A partir de C++20 se permite importar los símbolos de un enumerado-clase mediante la cláusula
using
:Permitir conversiones a formaciones abiertas (DT P0388R4)
WIP.
Funciones miembro especiales condicionalmente triviales (DT P0848R3)
WIP.
Parcheando la deducción de parámetros plantilla de clase (DT P1021R5)
WIP.
Deprecar
volatile
(DT P1152R4)WIP.
Librería.
Extender
<chrono>
para manejar calendarios y zonas horarias (DT P0355R7).Se incorpora a la librería de manejo de tiempo
Ejemplo.<chrono>
utilidades para manejar calendarios y zonas horarias:Conversión estándar a bits (documento técnico P0476R2).
En programación a bajo nivel, suele ser necesario interpretar un dato como si fuera otro; en otras palabras: mantener la misma representación binaria pero obteniendo un dato de diferente tipo.
Normalmente se usa
reinterpret_cast
o type punning mediante uniones para conseguirlo, pero éstos métodos son propensos a errores, lo más seguro es usar unstd::aligned_storage
sobre el que copiar los datos, pero es incómodo y costoso.La nueva cabecera
<bit>
proporciona herramientas para acceder, manipular y procesar tanto secuencias de bits como bits individuales de una forma menos propensa a errores y más flexible: asegura que los tamaños de los tipos de entrada y de salida coincidan, garantiza que ambos tipos sean copiables y hace que la expresión se calcule en tiempo de compilación cuando sea posible.Librería de formato de texto (DT P0645R10).
Las herramientas de escritura de texto de C++ son difíciles de entender y usar, el encadenado de
Ejemplo.std::ostream
y los formateos de<iomanip>
en ocasiones se quedan cortos y no ofrecen una suficiente flexibilidad, en ocasiones se delega aprintf
por claridad o costumbre. Este documento técnico propone una alternativa a el formateo de texto con la flexibilidad deprintf
y la seguridad destd::ostream
.La librería de formato de texto acepta argumentos posicionales implícitos y explícitos:
Constantes matemáticas (DT P0631R8).
Este documento técnico propone una nueva cabecera
<numbers>
y espacio de nombresnumbers
. Se incluyen varias constantes matemáticas de uso común como e, π, inversa de π… en formato de variable plantilla:Sufijos para
ptrdiff_t
ysize_t
(DT P0330R3)El siguiente código provoca un error de compilación:
La variable
i
se deduce comoint
mientras quef
se deduce como el retorno destd::vector::size
(que suele definirse comostd::size_t
), el siguiente código corrige el problema:Pero pierde flexibilidad. Dado que no existen literales de tipo
Ejemplo.std::size_t
se propone un sufijo:El sufijo
zu
(siz
eu
nsigned) soluciona el problema:Evolución.
Excepciones determinísticas sin coste:
throw
valores (DT P0709R4)WIP.
using
de enumerado (DT P1099R5)WIP.
Soporte a la configuración de clases (DT P1112R2)
WIP.
constinit
(DT P1143R2)WIP.
Añadir texto informativo a
[[nodiscard]]
(DT P1301R4)WIP.
Evolución de librería.
Integrar simd con algoritmos paralelos (DT P0350R3)
WIP.
Hacer que
std::string
ystd::vector
seanconstexpr
(DT P0980R1 y P1004R2)WIP.
Librería de Conceptos (documento técnico P0898R2).
Los conceptos serán una herramienta de C++ para hacer verificaciones sobre los tipos de los parámetros en tiempo de compilación. Es una utilidad que se lleva desarrollando desde C++11 y aunque aún no ha sido incorporada al lenguaje hay varios compiladores que le dan soporte, lo que hace pensar que será aprobada en breve. Para evitar desarrollar conceptos desde cero se propone una librería de conceptos que ofrezca los más comunes.
Ejemplo.
Usamos el concepto
Copyable
para que una función sólo acepte tipos que se puedan copiar:Clases como parámetros no-tipo en plantillas (documento técnico P0732R2).
C++ sólo permite datos que puedan ser evaluados en tiempo de compilación para verificar su unicidad como argumentos para parámetros no-tipo en plantillas. Esto limita el tipo de estos parámetros a enteros y punteros o referencias a datos o funciones con enlazado externo.
En otras palabras, se necesita garantizar que dada una plantilla con parámetro no-tipo, tiene que ser cierto que
&P<a> == &P<b>
cuandoa == b
, pero las clases de C++ no son por defecto comparables por igualdad ni el operador de igualdad forma parte de las funciones especiales que auto-genera el compilador. Así que este documento técnico propone usar el operador de comparación a tres bandas (apodado operador nave espacial<=>
) ya que se ha propuesto que éste si sea auto-generado por el compilador.Ejemplo.
Este código sería válido en C++20 pero no lo sería en estándares anteriores:
Reflexión estática (documento técnico P0275R4).
Según la Wikipedia, la reflexión es:
Este documento técnico propone añadir utilidades de reflexión a C++, esta reflexión sería estática (disponible en tiempo de compilación), para ello se añadiría al lenguaje la palabra clave
reflexpr
que aplicada sobre una definición, devolverá un objeto que contenga información de la misma.Ejemplo.
Podemos obtener el nombre de un parámetro así:
Usar
[[nodiscard]]
en la librería estándar (documento técnico P0600R1).Este documento técnico propone añadir el atributo
[[nodiscard]]
en la librería estándar cuando no usar el valor de retorno:De momento se valora marcar como
[[nodiscard]]
std::async()
,std::launder
,std::allocate
yempty
en contenedores.Flujo de salida con sincronización (documento técnico P0053R7).
El estándar garantiza que los flujos de salida de datos no producirán condiciones de carrera, pero no garantiza que enviar datos a esos flujos produzca un efecto perceptible; para que esto sea así se requiere un mecanismo de sincronización.
Este documento técnico propone añadir al estándar
basic_osyncstream
que envuelva un flujo de datos al que transferirá datos cuando se llame su destructor, de esta manera garantiza que los datos se envíen al flujo incluso en presencia de una excepción.Ejemplo.
Constantes matemáticas estandarizadas (documento técnico P0631R5).
Las constantes matemáticas como π y e son usadas frecuentemente en algoritmos pero no existe una definición de las mismas en ninguna cabecera estandarizada. Son muy fáciles de definir, pero es tan extraño como hacer una reserva en un restaurante en el que te piden que traigas tu propio salero.
Para suplir esta carencia, este documento técnico propone crear una colección de variables plantilla con los valores de las constantes más usadas, por citar algunas:
Ejemplo.
Con tan sólo incluir la cabecera
<math>
podremos usar estas constantes:Co-rutinas (documento técnico N3985).
Según la Wikipedia una co-rutina es:
几种编程语言原生支持协程,本文档提出让协程成为 C++ 标准的一部分。