C++23 es el estándar esperado para el lenguaje de programación C++ .
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) {
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
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 espeluznanteHasta 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[]
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.
La lista de indulgencias es larga y está relacionada con dos cosas:
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
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 ;Los caracteres de los conjuntos Unicode XID_Start (inicio) y XID_Continue (otros) ahora se permiten en los identificadores .
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.
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.
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.
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 #endifTodos los principales compiladores en realidad funcionan de esta manera.
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.
"\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] .
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
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 }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')
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 garantizadoInicialmente fue:std::cout << std::format("Hello, {}! You have {} mails", username, email_count);
Eso…
Está disponible uno más ligero [47] . std::print("Привет, {}! У вас {} писем", username, email_count);
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] .
C++ | |
---|---|
Peculiaridades | |
algunas bibliotecas | |
compiladores | |
influenciado | |
|