C++23

C++23 es el estándar esperado para el lenguaje de programación C++ .

Prohibido y eliminado

Eliminado

Prohibido

Prohibición levantada

Idioma

Cambios menores

si consteval

El anterior , hizo una función incorporada del compilador, resultó ser erróneo [12] . Por ejemplo: std::is_constant_evaluated()

constexpr size_t strlen ( char const * s ) { //if constexpr (std::is_constant_evaluated()) { Fue, no llamó a la versión del ensamblador if consteval { // Se convirtió en ( const char * p = s ; ; ++ p ) { si ( * pags == '\0' ) { return static_cast < std :: size_t > ( p - s ); } } } más { __asm__ ( "Algo optimizado para SSE" ); } }

Por supuesto, los compiladores emiten una advertencia, pero no es obvio qué hacer es correcto , de lo contrario, la versión optimizada del ensamblador no se ejecutará en absoluto. if (std::is_constant_evaluated())

La segunda razón es la interacción entre y . constexprconsteval

consteval int f ( int i ) { return i ; } constexpr int g ( int i ) { // if (std::is_constant_evaluated()) { Was, not compiled if consteval { // Ahora devuelve f ( i ) + 1 ; } más { volver 42 ; } }

Este código no se compiló en absoluto; no puede llamar a una función consteval desde aquí.

Las llaves en la parte entonces son obligatorias, pero en la parte else se pueden omitir. Parece imposible escribir. La función anterior no está prohibida, es extremadamente rara, pero necesaria. if (consteval && n < 0) {

auto(x) es una copia temporal de un objeto

Una manera fácil de obtener un objeto como temporal, como [12] :

void pop_front_alike ( Contenedor automático & x ) { std :: borrar ( x.begin ( ), x.end ( ) , automático ( x.front ( ) ) ) ; }

x.front() - error: según el contenedor, esta referencia buscará en otro objeto o en la memoria vacía.

El siguiente código es correcto, pero el auditor puede verse tentado a eliminar erróneamente la variable . a

automático a = x . frente (); std :: borrar ( x.begin ( ), x.end ( ) , a ) ;

En la programación de plantillas, este tipo puede ser difícil de obtener:

usando T = std :: decay_t < decltype ( x . front ()) > ; std :: borrar ( x.begin ( ), x.end ( ) , T ( x.front ( ) )) ) ;

El nombre se eliminó por dos razones: prvalue es un concepto altamente técnico y un comportamiento inapropiado para las matrices (dará un puntero). prvalue_cast

Operación de indexación multidimensional (corchetes)

Métodos existentes [13] :

matriz ( 1 , 2 , 3 , 4 , 5 ) = 42 ; // se ve horrible array [{ 1 , 2 , 3 , 4 , 5 }] = 42 ; // muy incomprensible y desagradable de escribir array [ 1 ][ 2 ][ 3 ][ 4 ][ 5 ] = 42 ; // un poco mejor, pero debajo del capó es espeluznante

Hasta ahora, solo para tipos personalizados [14] .

búfer int [ 2 * 3 * 4 ] = { }; auto s = mdspan < int , extensions < 2 , 3 , 4 >> ( búfer ); s [ 1 , 1 , 1 ] = 42 ;

Las diferentes bibliotecas implementan la sintaxis que falta de diferentes maneras, pero en cualquier caso, esto no es compatible con la sintaxis de las matrices estándar y dificulta la búsqueda automática de errores y la inserción (implementación de una función directamente en el código de llamada).

El tema de discusión sigue siendo: ¿es necesario para matrices estándar? si relajar los requisitos y permitirlo fuera de la clase. operator[]

Esta-opciones

Una de las características de C++, la corrección constante, conduce a la duplicación del código oa la escritura de métodos de delegación. Se propone una solución a esto a través de plantillas [15]

///// FUE ///// clase TextBlock { público : char const & operador []( tamaño_t posición ) const { // ... devuelve el texto [ posición ]; } char & operador []( posición size_t ) { volver const_cast < carácter &> ( static_cast < TextBlock const &> ( esto )[ posición ] ); } // ... }; ///// CONVIÉRTETE ///// clase TextBlock { público : template < typenameSelf > _ auto & operador []( este Self && self , posición size_t ) { // ... devuelve self . texto [ posición ]; } // ... };

Aún no se ofrecen métodos de extensión , pero serán posibles en el futuro.

Requisitos reducidos para constexpr

La lista de indulgencias es larga y está relacionada con dos cosas:

  • Ahora constexpr significa que hay al menos una ruta de ejecución posible al compilar.
  • Las bibliotecas siempre van a la zaga del idioma.

Por lo tanto, ahora es posible escribir una función constexpr que, sin un conjunto de argumentos, se puede ejecutar en la compilación [16] .

También se permiten en las funciones constexpr goto , variables de tipos no literales, variables estáticas/intra-thread. Si se pasa alguna de estas líneas durante la compilación, la función se evalúa en la ejecución. elevado a 202103L [17] . __cpp_constexpr

Operador estático()

Elimina una instrucción de máquina si la clase no tiene datos y la inserción falla [18] . Por ejemplo, en un árbol autoequilibrado con un orden no estándar (estaba en C++03 ) y búsqueda heterogénea ( C++14 ), es posible el siguiente código:

estructura CustomCompare { usando es_transparente = int ; // Operador bool estático de búsqueda heterogénea () ( std :: string_view a , std :: string_view b ) // era const, se convirtió en estático { return someCustomLess ( a , b ); } }; std :: set < std :: string , CustomCompare > cosas ;

Codificaciones de caracteres

Caracteres permitidos en los identificadores

Los caracteres de los conjuntos Unicode XID_Start (inicio) y XID_Continue (otros) ahora se permiten en los identificadores .

  • Se permiten letras y números de diferentes alfabetos, incluidos caracteres chinos , cuneiformes y letras matemáticas latinas/árabes, muchas de las cuales son caracteres similares a letras.
  • Se permiten caracteres de tipo "letra/modificador": se permite 02C6 ˆ "modificador-cap", y 02DA ˚ "círculo superior" es de tipo "carácter/modificador" y está prohibido.
  • Se permite la combinación de marcas, incluidos los selectores de estilo.
  • Se prohíben emoji , caracteres no alfabéticos de ingeniería y matemáticas, caracteres de formato (caracteres invisibles responsables del procesamiento de texto, incluidos ZWJ y ZWNJ) .

El identificador debe normalizarse de acuerdo con el algoritmo de "composición canónica" (NFC, desensamblar caracteres monolíticos en componentes y volver a ensamblar). Si no, el programa es incorrecto.

Este cambio solo hace que la compatibilidad con Unicode sea más consistente, pero no soluciona los problemas de los ataques a través de cadenas aparentemente idénticas [19] . Los métodos para pasar dichos caracteres al enlazador dependen de la implementación.

Los literales wchar_t no codificados y de varios caracteres no están permitidos

Diferentes compiladores actuaron de manera diferente en (facepalm emoji ) en un wchar_t de doble byte (Windows), . Ambos están ahora prohibidos [20] . L'\U0001F926'L'ab'

Los literales de caracteres de varios caracteres aún funcionan, son de tipo int. La implementación determina cuántos caracteres se permiten y cómo se recopilarán en un solo número.

Los conceptos de "codificación de traducción", "codificación de rendimiento"

Es legal que uno pueda ser diferente del otro [21] y  es una unidad de una codificación de rendimiento amplia y específica de la implementación [22] . wchar_t

UTF-8 como codificación de traducción multiplataforma debe ser compatible incondicionalmente con todos los compiladores [23] . La marca de orden de bytes se ignora a menos que entre en conflicto con las marcas del compilador. Si el archivo se reconoce como UTF-8, no debe contener combinaciones de código incorrectas; sin embargo, puede haber combinaciones correctas correspondientes a caracteres que aún no existen.

Los valores numéricos de los caracteres literales en el preprocesador coinciden con la codificación de ejecución

Solía ​​depender de la implementación, pero resultó que el objetivo principal de esta función es determinar la codificación de ejecución [24] . Por ejemplo, código de SQLite :

/* Comprobar si la máquina está utilizando EBCDIC. (Sí, lo crea o no, todavía hay máquinas que usan EBCDIC). */ #if 'A' == '\301' # define SQLITE_EBCDIC 1 #else # define SQLITE_ASCII 1 #endif

Todos los principales compiladores en realidad funcionan de esta manera.

Se permite nuevamente inicializar matrices de caracteres y caracteres sin firmar con un literal UTF-8

Las tres líneas están rotas en C++20, funcionan de nuevo en C++23 [25] .

const char * a = u8 "a" ; const char b [] = u8 "b" ; const char sin signo c [] = u8 "c" ;

Al final resultó que, tal ruptura hizo que las funciones constexpr fueran más complicadas e interfirió con la compatibilidad con C.

Nuevas capturas de pantalla

"\u{1F926}"para un punto de código Unicode, para octal y para hexadecimal [26] . "\o{123}""\x{AB}"

Está prohibido romper dichos escudos ( )."\x{4" "2}"

"\N{LATIN CAPITAL LETTER A WITH MACRON}"le permite referirse a un símbolo por su nombre Unicode [27] .

Cambios editoriales

  • La concatenación de barra invertida ahora permite espacios después de la barra invertida [28] . Así es como funcionaban GCC, Clang e ICC, y MSVC dejó un hueco.
  • El compilador no puede reorganizar los campos de un objeto si tienen una longitud distinta de cero y derechos de acceso diferentes [29] . Así actuaron MSVC, GCC, Clang.
  • Concatenación de cadenas con prefijos de codificación en conflicto como . De los principales compiladores, solo SDCC admite esto  : toma el primero de los prefijos [30] .L"" u""
  • Directiva legalizada #warningapoyada por todos [31] .
  • Reglas de movimiento implícitas simplificadas al regresar de una función [32] .
  • Tipos enteros extendidos específicos del proveedor refactorizados [33] .
  • Se aclaró el estado de los archivos de encabezado C: ahora son para compatibilidad con versiones anteriores. Un archivo que no debe ser simultáneamente un archivo C válido no debe incluirlos [34] .

Armonización con C

  • Etiqueta sin operador permitida: [35] .{ goto a; ++x; a: }
  • Apoyo _ No hay análogo [36] .<stdatomic.h><cstdatomic>
  • Se permite nuevamente inicializar matrices de caracteres y caracteres sin firmar con un literal UTF-8 (descrito anteriormente).

Biblioteca

Cambios menores

  • exchangerecibió un condicional noexcept - si el objeto se crea con un movimiento y se asigna por copia sin lanzar excepciones [37] .
  • Heterogéneos y en contenedores asociativos [38] . Por ejemplo, la clave de almacenamiento es y la clave de acceso es .extracterasestringstring_view
  • string[_view].contains - a menudo necesita verificar la presencia de una subcadena sin averiguar dónde está la coincidencia [39] .
  • Una nueva función , que usa más completamente las características del mecanismo de asignación de memoria [40] . Los contenedores de tamaño variable migrarán gradualmente a él.Allocator.allocate_at_least
  • Una familia de constantes  , por ejemplo, para realizar un seguimiento de la migración de una biblioteca de antigua a nueva [41] .is_scoped_enumenumenum class
  • Una función para convertir , cuyo nombre es más comprensible y menos propenso a errores [42] .to_underlyingenum int
  • Función en el encabezado para cambiar el orden de los bytes en los números [43] .byteswap<bit>
  • iostream ahora puede imprimir punteros volátiles, al igual que los punteros normales [44] .

std::move_only_function

std::functionse convirtió en una de las partes más "pesadas" de la biblioteca STL. Al deshacerse de varias funciones (no se pueden copiar, faltan campos y  ) puede obtener un objeto mucho más ligero [45] . Y, por supuesto, este objeto puede funcionar con ganchos no copiables. targettarget_type

Operaciones de mónadas en std::opcional

Una mónada  es una característica estándar de los lenguajes funcionales para realizar una secuencia de acciones.

En matemáticas, una secuencia de funciones se escribe como , lo que no siempre es conveniente; en programación, algo así como . x.f().g().h()

std::opcional  es un contenedor bastante simple, cuyo significado es almacenar un objeto o nada. Los controles de "nada" ocupan una gran parte del trabajo con opcionales, pero ¿y si, en el proceso de transformación de la imagen, no hay un gato en ella? Pero, ¿y si no hay lugar para dibujar un arco? [46]

std :: opcional < imagen > get_cute_cat ( const imagen e img ) { return crop_to_cat ( img ) // imagen → opcional; [nullopt] no hay ningún gato en la imagen . and_then ( add_bow_tie ) // imagen → opcional; [nullopt] en ninguna parte para agregar un arco . and_then ( make_eyes_sparkle ) // imagen → opcional; [nullopt] no puede ver los ojos . transform ( make_smaller ) // imagen → imagen . transformar ( añadir_arcoiris ); // imagen → imagen }

string::resize_and_overwrite

Se utiliza para una optimización extrema en la unión de cadenas y API de bajo nivel:

int compress ( void * out , size_t * out_size , const void * in , size_t in_size ); std :: string CompressWrapper ( std :: string_view entrada ) { std :: cadena comprimida ; comprimido _ resize_and_overwrite ( entrada . tamaño (), [ entrada ]( char * buf , std :: size_t n ) noexcept { estándar :: tamaño_t tamaño_comprimido = n ; auto is_ok = comprimir ( buf , & tamaño_comprimido , entrada . datos (), entrada . tamaño ()); afirmar ( está_bien ); devuelve tamaño_comprimido ; }); volver comprimido ; }

Surge la pregunta: ¿qué se optimizó en comparación con los dos ? [13] El hecho es que el costo de asignar memoria no depende mucho de la longitud del búfer y, en la mayoría de los casos, se asignará mucha más memoria al búfer de la que realmente se requiere para la cadena comprimida. La nueva función no inicializa el búfer y la puesta a cero de una sección muy larga de memoria - . resizememset( compressed.data(), compressed.size(), '\0')

spanstream - un reemplazo para lo prohibido en C++98 strstream

Había un strstream, un flujo de datos que se ejecutaba en una matriz de longitud limitada. Prohibido en C++98, se ha propuesto otro mecanismo similar.

salida de caracteres [ 30 ]{}; ospanstream os { span < char > { salida }}; os << 10 << 20 << 30 ; const automático sp = os . lapso (); ASSERT_EQUAL ( 6 , sp . tamaño ()); ASSERT_EQUAL ( "102030" , std :: cadena ( sp . datos (), sp . tamaño ())); ASSERT_EQUAL ( static_cast < void *> ( salida ), sp . data ()); // sin copia de datos ASSERT_EQUAL ( "102030" , salida ); // terminado en nulo garantizado

imprimir

Inicialmente fue:std::cout << std::format("Hello, {}! You have {} mails", username, email_count);

Eso…

  • Alarga el código binario: los flujos son inherentemente pesados.
  • Sin soporte Unicode.
  • se ve feo

Está disponible uno más ligero [47] . std::print("Привет, {}! У вас {} писем", username, email_count);

Tipos fraccionarios opcionales

Nombre Bits de mantisa orden de bits Nota
flotar16_t 10 + implícito 1 5 Cumple con IEEE binario16
bfloat16_t 7 + implícito 1 ocho Los dos bytes superiores IEEE binary32 (≈float), utilizados en las bibliotecas de IA, de ahí el nombre de cerebro flotante
flotar32_t 23 + implícito 1 ocho Cumple con IEEE binary32, la mayoría de las implementaciones flotantes
flotar64_t 52 + implícito 1 once Cumple con IEEE binary64, la mayoría de las implementaciones de doble
flotar128_t 112 + implícito 1 quince Cumple con IEEE binary128

Las funciones matemáticas deben tener envolturas para todos los tipos admitidos, mientras que el cálculo real se puede realizar en un tipo más o menos exacto [48] .

Notas

  1. Fuente . Consultado el 8 de agosto de 2022. Archivado desde el original el 18 de julio de 2022.
  2. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2327r1.pdf
  3. Fuente . Consultado el 20 de julio de 2022. Archivado desde el original el 10 de junio de 2022.
  4. P2360R0: Ampliar declaración de inicio para permitir declaración de alias
  5. Edición 2397 del CWG
  6. P1102R2: ¡Abajo con ()! . Consultado el 9 de agosto de 2022. Archivado desde el original el 9 de agosto de 2022.
  7. Fuente . Consultado el 27 de julio de 2022. Archivado desde el original el 24 de mayo de 2022.
  8. Limitación de las conversiones contextuales a bool . Consultado el 27 de julio de 2022. Archivado desde el original el 27 de julio de 2022.
  9. Cambiar el alcance de lambda trailing-return-type . Consultado el 27 de julio de 2022. Archivado desde el original el 27 de julio de 2022.
  10. Fuente . Consultado el 27 de julio de 2022. Archivado desde el original el 22 de agosto de 2022.
  11. Fuente . Consultado el 1 de agosto de 2022. Archivado desde el original el 30 de julio de 2022.
  12. 1 2 `si consteval` . Consultado el 20 de julio de 2022. Archivado desde el original el 20 de julio de 2022.
  13. 1 2 C++23 - función congelar cierre / Sudo Null IT News Consultado el 28 de julio de 2022. Archivado desde el original el 14 de mayo de 2022.
  14. Fuente . Consultado el 20 de julio de 2022. Archivado desde el original el 24 de mayo de 2022.
  15. Deduciendo esto . Consultado el 27 de julio de 2022. Archivado desde el original el 12 de julio de 2022.
  16. Relajación de algunas restricciones constexpr . Consultado el 29 de julio de 2022. Archivado desde el original el 25 de julio de 2022.
  17. Variables no literales (y etiquetas y gotos) en funciones constexpr . Consultado el 20 de julio de 2022. Archivado desde el original el 24 de mayo de 2022.
  18. operador estático() . Consultado el 29 de julio de 2022. Archivado desde el original el 29 de julio de 2022.
  19. Sintaxis de identificador de C++ con el estándar Unicode Anexo 31 . Consultado el 27 de julio de 2022. Archivado desde el original el 12 de julio de 2022.
  20. Fuente . Consultado el 27 de julio de 2022. Archivado desde el original el 27 de julio de 2022.
  21. P2314R3: Conjuntos de caracteres y codificaciones . Consultado el 27 de julio de 2022. Archivado desde el original el 24 de mayo de 2022.
  22. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2460r2.pdf
  23. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2295r6.pdf
  24. Fuente . Consultado el 27 de julio de 2022. Archivado desde el original el 24 de mayo de 2022.
  25. D2513R3: Corrección de compatibilidad y portabilidad de char8_t
  26. Fuente . Consultado el 29 de julio de 2022. Archivado desde el original el 24 de mayo de 2022.
  27. Escapes de personajes universales nombrados . Consultado el 29 de julio de 2022. Archivado desde el original el 29 de julio de 2022.
  28. Fuente . Consultado el 27 de julio de 2022. Archivado desde el original el 24 de mayo de 2022.
  29. Fuente . Consultado el 27 de julio de 2022. Archivado desde el original el 24 de mayo de 2022.
  30. P2201R1: Concatenación literal de cadenas mixtas . Consultado el 27 de julio de 2022. Archivado desde el original el 27 de julio de 2022.
  31. Fuente . Consultado el 27 de julio de 2022. Archivado desde el original el 30 de julio de 2022.
  32. P2266R3: Movimiento implícito más simple . Consultado el 1 de agosto de 2022. Archivado desde el original el 24 de mayo de 2022.
  33. Limpieza de tipos de clase entera
  34. Aclarando el estado de los "encabezados C"
  35. Fuente . Consultado el 29 de julio de 2022. Archivado desde el original el 17 de junio de 2022.
  36. P0943R6: Compatibilidad con átomos de C en C . Consultado el 8 de agosto de 2022. Archivado desde el original el 8 de agosto de 2022.
  37. P2401R0: Agregar una especificación noexcept condicional a std::exchange . Consultado el 28 de julio de 2022. Archivado desde el original el 28 de julio de 2022.
  38. P2077R3: Sobrecargas de borrado heterogéneo para contenedores asociativos . Consultado el 29 de julio de 2022. Archivado desde el original el 24 de mayo de 2022.
  39. la cadena contiene la función . Consultado el 8 de agosto de 2022. Archivado desde el original el 8 de agosto de 2022.
  40. P0401R6: Proporcionar comentarios sobre el tamaño en la interfaz del asignador . Consultado el 8 de agosto de 2022. Archivado desde el original el 20 de julio de 2022.
  41. Fuente . Consultado el 8 de agosto de 2022. Archivado desde el original el 24 de mayo de 2022.
  42. P1682R3: std::to_underlying para enumeraciones . Consultado el 8 de agosto de 2022. Archivado desde el original el 8 de agosto de 2022.
  43. P1272R4: Intercambio de bytes por diversión&&nuf . Consultado el 8 de agosto de 2022. Archivado desde el original el 8 de agosto de 2022.
  44. P1147R1: Impresión de punteros 'volátiles'
  45. P0288R9: mover_solo_función . Consultado el 20 de julio de 2022. Archivado desde el original el 20 de julio de 2022.
  46. p0798R6: Operaciones monádicas para std::opcional . Consultado el 20 de julio de 2022. Archivado desde el original el 20 de julio de 2022.
  47. P2093R14: Salida formateada . Consultado el 29 de julio de 2022. Archivado desde el original el 24 de julio de 2022.
  48. P1467R9: Tipos de punto flotante extendidos y nombres estándar . Consultado el 29 de julio de 2022. Archivado desde el original el 29 de julio de 2022.