C++14

C++14  es el nombre no oficial de la versión ISO/IEC JTC1 del estándar C++ (nombre completo: " Estándar internacional ISO/IEC 14882:2014(E) Lenguaje de programación C++ ") [1] . Se puede pensar en C++ 14 como una pequeña extensión de C++ 11 que contiene principalmente correcciones de errores y mejoras menores. El Comité de Desarrollo de Nuevos Estándares publicó el borrador N3690 el 15 de mayo de 2013 [2] . El borrador de trabajo N3936 se publicó el 2 de marzo de 2014, el período de votación final se cerró el 15 de agosto de 2014 y el resultado (aprobación unánime) se anunció el 18 de agosto de 2014 [3] .

Dado que el desarrollo del estándar fue largo y no se determinó el año de lanzamiento de la versión final, también se usó el nombre "C++1y" durante el desarrollo, de forma similar a como se llamó "C+" al estándar C++11. +0x" antes de su lanzamiento (se esperaba el lanzamiento de esta versión hasta 2010).

Las características del idioma que se describen a continuación corresponden al borrador de trabajo N3797 . Puede haber ligeras diferencias en estos en comparación con la versión final del estándar .

Cambios de idioma

Esta sección presenta nuevas características del lenguaje central en C++14.

Inferencia de tipo de retorno para funciones

C++11 le permite inferir el tipo de retorno de las funciones lambda a partir del tipo de retorno de una expresión. C++14 extiende esta capacidad a todas las funciones. El nuevo estándar también describe la inferencia de tipos para funciones lambda, con una forma diferente a return expression;[4] .

Para utilizar la inferencia de tipo de devolución automática, se debe declarar una función con type autocomo el tipo de devolución, pero sin el especificador de cola de tipo de devolución de C++11:

auto DeduceReturnType (); // el tipo de devolución se definirá más adelante.

Si se devuelven varias expresiones en diferentes lugares del cuerpo de la función, todas estas expresiones deben tener un tipo inferido común [5] .

Las funciones que usan autoinferencia de tipo de retorno pueden usar declaración directa, pero solo se pueden usar después de que se hayan definido. Estas definiciones deben estar disponibles en la misma unidad de traducción en la que se utilizan.

Es posible usar la recursión en tales funciones , pero la llamada recursiva debe realizarse después de al menos un valor de retorno en esta función [5] :

Corrección automática ( int i ) { si ( yo == 1 ) devolver yo ; // int se muestra como tipo de valor devuelto volver Correcto ( i -1 ) + i ; // ahora puedes llamar a } autoincorrecto ( int i ) { _ si ( yo != 1 ) devuelve Incorrecto ( i -1 ) + i ; // lugar inapropiado para la recursividad. Sin devolución previa. más devolver yo ; // int se muestra como tipo de retorno }

Inferencia de tipos alternativos al declarar

C++ 11 agregó dos formas de inferir tipos. autole permitió crear variables con un tipo basado en una expresión asignada. decltypepermitió determinar el tipo resultante de una expresión arbitraria. Sin embargo, los tipos inferidos por decltypey autodiferían entre sí. En particular, autosiempre infiere un tipo de no referencia como si fuera procesado std::remove_reference, mientras que auto&&siempre infiere un tipo de referencia. Sin embargo, el resultado decltypepuede ser un tipo de referencia o un tipo sin referencia, según la expresión que se procese [4] :

ent i ; int && f (); auto x3a = yo ; // tipo de cl (x3a) - int tipo de cl ( i ) x3d = i ; // decltype(x3d) - int auto x4a = ( i ); // tipo de cl (x4a) - int tipo de cl (( i )) x4d = ( i ); // decltype(x4d) - int& auto x5a = f (); // tipo de cl (x5a) - int tipo de cl ( f ()) x5d = f (); // tipo de declaración (x5d) - int&&

C++14 agregó la sintaxis decltype(auto). Esta sintaxis le permite utilizar reglas de decltypedeclaración auto. Solo tiene sentido en el código repetitivo.

La sintaxis decltype(auto)también se puede usar para inferir tipos de devolución especificando el tipo de devolución de la función en lugar de decltype(auto)[ 5] . auto

Reducción de restricciones en expresiones constantes

C++11 introduce el concepto de constexprfunciones: funciones que se pueden ejecutar en tiempo de compilación. Los valores que devuelven se pueden usar en operaciones que requieren una expresión constante, como un argumento de plantilla. Sin embargo, en C++11 constexpr, las funciones pueden contener solo una expresión de retorno (así como static_assertvarias otras declaraciones).

En C++14, estas restricciones se eliminan parcialmente. constexpr-funciones ahora pueden contener los siguientes elementos [4] :

  • Cualquier anuncio que no sea:
    • statico thread_localvariables;
    • declaraciones de variables sin inicializadores.
  • Instrucciones de bifurcación condicional ify switch.
  • Todas las instrucciones de bucle, incluidas las forde rangos.
  • Expresiones que cambian los valores de los objetos si el tiempo de vida de estos objetos comenzó en la constexprfunción -. Esto también incluye llamadas a cualquier const constexprfunción miembro no estática.

La instrucción gotono está permitida en una función de constexprC++14.

Las restricciones para llamar a funciones que no constexprson funciones siguen vigentes. Por lo tanto, si se usa forpara rangos, funciones beginy endcontenedores, debe sobrecargarse como constexpr. Para un tipo std::initializer_listincorporado, las funciones se begin/enddefinen como constexpr, tanto local como globalmente.

Además, en C++ 11, todos los métodos no estáticos declarados con constexprfueron tratados implícitamente como constfunciones con respecto a this. Esta restricción ha sido eliminada; los métodos no estáticos ahora pueden ser no const[6] . Sin embargo, como se mencionó anteriormente, un no const constexprmétodo solo puede cambiar campos de clase si el tiempo de vida de ese objeto comenzó durante la evaluación de una expresión constante.

Plantillas variables

En versiones anteriores de C++ , las plantillas se limitaban a funciones y clases. C++14 le permite crear variables de plantilla.

plantilla < typenameT > _ constexpr T pi = T ( 3.1415926535897932385 ); // Se aplican las reglas habituales de especialización: plantilla <> constexpr const char * pi < const char *> = "pi" ;

En este ejemplo, se define una plantilla de variable a la pique se puede acceder para obtener el valor de pi para varios tipos (por ejemplo, 3al leer un tipo entero; valor más cercano a float, doubleo long doubleal leer como float, doubleo long double, respectivamente, etc.).

Dichas declaraciones y definiciones incluyen las reglas de plantilla habituales, incluidas las reglas de especialización [7] [8] .

Inicialización agregada de clases con inicializadores de campo

C++11 introdujo inicializadores de campo de clase, que son expresiones que se aplican a los campos en el nivel de clase si el constructor no los inicializa por sí solo. La definición de agregados se cambió para excluir explícitamente todas las clases con inicializadores de miembros, por lo que la inicialización de agregados no era posible para ellos.

C++14 elimina esta restricción [4] y permite la inicialización agregada de clases con inicializadores de campo. Si la lista de inicializadores entre llaves no proporciona un valor para este argumento, entonces el inicializador de campo [9] se hace cargo .

Literales binarios

Los literales numéricos en C++14 se pueden especificar en forma binaria [4] . La sintaxis utiliza los prefijos 0bo 0B. También se utiliza una sintaxis similar en Java , Python , Perl y D.

Separadores de mil

En C++14, puede usar el apóstrofe para separar arbitrariamente bits en literales numéricos [10] . En algunos casos, esto simplifica la percepción de grandes constantes numéricas en el código y mejora la legibilidad del código.

auto integer_literal = 1'000'000 ; literal_punto_flotante automático = 0.000'015'3 ; literal_binario automático = 0b0100'1100'0110 ; auto ejemplo_tonto = 1'0'0'000'00 ;

Funciones lambda genéricas

En C++11, los parámetros de la función lambda debían declararse con tipos específicos. C++14 elimina esta restricción y permite que los parámetros de la función lambda se declaren con un especificador de tipo auto[7] .

auto lambda = []( auto x , auto y ) { return x + y ;};

La inferencia de tipo para parámetros de funciones lambda genéricas sigue reglas similares a la inferencia de tipo para autovariables (pero no completamente idénticas). El código anterior es equivalente al siguiente [11] :

estructura unnamed_lambda { plantilla < nombre de tipo T , nombre de tipo U > operador automático ()( T x , U y ) const { return x + y ;} }; auto lambda = unnamed_lambda ();

Captura de expresiones para funciones lambda

Las funciones lambda de C++11 le permiten capturar variables declaradas en un ámbito externo pasándolas por referencia o por valor. Esto significa que no puede capturar por valor variables de tipos que solo se pueden mover (pero no copiar) [12] . C++14 le permite capturar variables con inicialización de expresión arbitraria. Esto hace posible capturar variables con movimiento de valores y declarar variables con nombres no declarados en ámbitos superiores [7] .

Las expresiones se capturan usando inicializadores:

auto lambda = [ valor = 1 ] { valor de retorno ;};

La función lambda lambdadevolverá 1 porque valuese ha activado el inicializador apropiado para el parámetro. El tipo del parámetro capturado se deduce del tipo del inicializador, similar a declarar una variable con el especificador auto.

Esta función se puede utilizar para capturar con movimiento utilizando la función estándar std::move:

auto ptr = hacer_único < int > ( 10 ); auto lambda = [ valor = std :: mover ( ptr )] { retorno * valor ;};

Atributo [[deprecated]]

El atributo deprecatedle permite marcar entidades como obsoletas. Todavía se puede acceder a estas entidades, pero se emite una advertencia en tiempo de compilación. El argumento deprecatedpuede ser un literal de cadena que explique el motivo de desaprobación y/o el posible reemplazo.

[[ obsoleto ]] intf ( ); [[ obsoleto ( "g() no es seguro para subprocesos. Use h() en lugar de g()" )]] vacío g ( int & x ); vacío h ( int & x ); prueba nula () { int a = f (); // advertencia: 'f' está en desuso g ( a ); // advertencia: 'g' está en desuso: g() no es seguro para subprocesos. Usa h() en lugar de g() }

Nuevas funciones en la biblioteca estándar

Mutexes y candados compartidos

C++14 agrega mutexes compartidos y un nuevo tipo de bloqueo para mutexes compartidos [13] [14] .

Búsqueda heterogénea en contenedores asociativos

La biblioteca estándar de C++ define cuatro clases de contenedores asociativos. Estas clases permiten al usuario buscar valores en base a un valor de ese tipo. Los contenedores de mapas permiten al usuario especificar una clave y un valor, mientras busca la clave y devuelve el valor. Sin embargo, la búsqueda siempre se ha realizado en un tipo particular de clave, ya sea la clave, como en el mapa, o el valor en sí mismo, como en el conjunto.

C++14 permite que los contenedores asociativos se indexen por un valor de un tipo arbitrario, siempre que haya un operador de comparación sobrecargado que pueda comparar el valor de ese tipo con el valor del tipo de clave del contenedor [15] . Esto permite que los contenedores de mapa con un tipo de clave sean indexados por std::stringexpresiones de tipo const char*utilizando el operador de comparación sobrecargado operator<.

Para mantener la compatibilidad con versiones anteriores, las búsquedas heterogéneas solo se permiten si el comparador pasado al contenedor asociativo admite dicha búsqueda. Clases de biblioteca estándar std::less(predeterminadas para conjuntos y contenedores de mapas) y std::greaterpermiten búsquedas heterogéneas [16] .

Literales estándar definidos por el usuario

C++11 tiene una sintaxis para sufijos literales definidos por el usuario, pero ninguno de ellos se usa en la biblioteca estándar. C++14 agrega los siguientes literales estándar [15] :

  • "s" para crear diferentes std::basic_stringtipos.
  • "h", "min", "s", "ms", "us" y "ns" para crear los intervalos de tiempo correspondientes std::chrono::duration.
cadena str = "hola mundo" s ; crono :: duración dur = 60 s ;

Los dos literales "s" no se afectan entre sí porque el literal de cadena solo funciona en cadenas, mientras que el segundo literal solo funciona en números [17] .

Direccionamiento de tuplas por tipo

std::tuple, introducido en C++11, le permite agregar varios valores escritos que se indexarán en el momento de la compilación. C++14 amplía la funcionalidad de las tuplas para permitir el acceso a elementos de una tupla no solo por índice, sino también por tipo [15] . Si la tupla contiene más de un elemento del tipo solicitado, la búsqueda generará un error en tiempo de compilación [18] :

tupla < cadena , cadena , int > t ( "foo" , "barra" , 7 ); int i = obtener < int > ( t ); // i == 7 int j = obtener < 2 > ( t ); // igual que antes: j == 7 string s = get < string > ( t ); // error de tiempo de compilación debido a la ambigüedad

Otros cambios a la biblioteca estándar

std::make_uniquese puede usar de la misma manera que std::make_sharedpara los objetos std::unique_ptr[7] .

Para std::integral_constantagregar una sobrecarga operator()que devuelve un valor constante [15] .

Por analogía con las funciones globales std::begin/std::end, se han agregado funciones std::cbegin/std::cendque devuelven iteradores constantes al principio y al final del rango.

Notas

  1. ISO/IEC 14882:2014 - Tecnología de la información - Lenguajes de programación - C++ . ISO (14 de enero de 2014). Fecha de acceso: 26 de enero de 2015. Archivado desde el original el 29 de enero de 2017.
  2. Borrador del comité, Estándar para el lenguaje de programación C++ (PDF). ISO (15 de mayo de 2013). Consultado el 24 de julio de 2014. Archivado desde el original el 21 de enero de 2022.
  3. Sutter, Herb (18 de agosto de 2014), ¡Tenemos C++14! , < https://isocpp.org/blog/2014/08/we-have-cpp14 > . Consultado el 18 de agosto de 2014. Archivado el 19 de agosto de 2014 en Wayback Machine . 
  4. 1 2 3 4 5 Wong, Michael The View from the C++ Standard meeting April 2013 Part 3 . Café C/C++ (30 de abril de 2013). Consultado el 14 de junio de 2013. Archivado desde el original el 13 de octubre de 2013.
  5. 1 2 3 Merrill, Jason N3638 Deducción de tipo de retorno para funciones normales (Revisión 5) (17 de abril de 2013). Consultado el 14 de junio de 2013. Archivado desde el original el 25 de agosto de 2013.
  6. Smith, Richard N3652 Restricciones relajantes en funciones constexpr (18 de abril de 2013). Consultado el 24 de julio de 2014. Archivado desde el original el 25 de agosto de 2013.
  7. 1 2 3 4 Sutter, Emblem Trip Report: reunión de primavera de 2013 de ISO C++ . isocpp.org (20 de abril de 2013). Consultado el 14 de junio de 2013. Archivado desde el original el 20 de agosto de 2017.
  8. Dos Reis, Gabriel N3651 Plantillas variables (Revisión 1) (PDF) (19 de abril de 2013). Consultado el 24 de julio de 2014. Archivado desde el original el 25 de agosto de 2013.
  9. Vandevoorde, Daveed; Voutilainen, Ville N3653 Inicializadores y agregados de miembros (17 de abril de 2013). Consultado el 24 de julio de 2014. Archivado desde el original el 25 de agosto de 2013.
  10. Cuervo, Lawrence; Smith, Ricardo; Snyder, Jeff; Vandevoorde, Daveed N3781 Comillas simples como separador de dígitos (25 de septiembre de 2013). Consultado el 15 de octubre de 2014. Archivado desde el original el 13 de abril de 2014.
  11. Faisal, Vali; Sutter, hierba; Abrahams, Dave N3649 Expresiones Lambda genéricas (polimórficas) (Revisión 3) (19 de abril de 2013). Consultado el 24 de julio de 2014. Archivado desde el original el 25 de agosto de 2013.
  12. Mover captura en Lambda . desbordamiento de pila . Consultado el 24 de julio de 2014. Archivado desde el original el 24 de enero de 2013.
  13. Wong, Michael The View from the C++ Standard meeting April 2013 Part 3 . Café C/C++ (30 de abril de 2013). Consultado el 14 de junio de 2013. Archivado desde el original el 13 de octubre de 2013.
  14. Howard, Hinnant; Vollmann, Detlef; Boehm, Hans N3659 Bloqueo compartido en C++ (Revisión 2) (19 de abril de 2013). Consultado el 24 de julio de 2014. Archivado desde el original el 19 de agosto de 2013.
  15. 1 2 3 4 Wong, Michael The View from the C++ Standard meeting April 2013 Part 2 . Café C/C++ (26 de abril de 2013). Consultado el 14 de junio de 2013. Archivado desde el original el 13 de octubre de 2013.
  16. N3657 Agregar búsqueda de comparación heterogénea a contenedores asociativos (rev. 4) (19 de marzo de 2013). Consultado el 24 de julio de 2014. Archivado desde el original el 19 de agosto de 2013.
  17. Peter, Sommerlad N3642 Literales definidos por el usuario para tipos de biblioteca estándar (parte 1 - versión 4) (PDF) (18 de abril de 2013). Consultado el 24 de julio de 2014. Archivado desde el original el 25 de agosto de 2013.
  18. Spertus, Mike N3670 Redacción para abordar tuplas por tipo: revisión 2 (19 de abril de 2013). Consultado el 24 de julio de 2014. Archivado desde el original el 19 de agosto de 2013.