Compatibilidad con las características de C++11/14/17 (C++ moderno)

 

Para obtener la documentación más reciente de Visual Studio 2017 RC, consulte Documentación de Visual Studio 2017 RC.

En este artículo se explican las características de C++11/14/17 en Visual C++.

Visual C++ implementa la mayoría de las características de la especificación principal del lenguaje C++11, así como muchas características de la biblioteca de C++14 y algunas de las características propuestas para C++17. En la tabla siguiente se enumeran las características principales del lenguaje C++11/14/17 y su estado de implementación para Visual C++ en Visual Studio 2010, Visual C++ en Visual Studio 2012 y Visual C++ en Visual Studio 2013, y en Visual Studio 2015.

Tabla de características principales del lenguaje C++11

Características principales del lenguaje C++11Visual Studio 2010Visual Studio 2012Visual Studio 2013Visual Studio 2015
Referencias a valor R v0.1, v1.0, v2.0, v2.1, v3.0v2.0v2.1*v2.1*v3.0
Calificadores de referenciasNoNoNo
Inicializadores de miembros de datos no estáticosNoNo
Plantillas variádicas v0.9, v1.0NoNo
Listas de inicializadoresNoNo
static_assert
auto v0.9, v1.0v1.0v1.0v1.0
Tipos de valor devueltos finales
Lambdas v0.9, v1.0, v1.1v1.0v1.1v1.1
decltype v1.0, v1.1v1.0v1.1**v1.1
Corchetes angulares de cierre
Argumentos predeterminados para plantillas de funcionesNoNo
Expresión SFINAENoNoNoNo
Plantillas de aliasNoNo
Plantillas Extern
nullptr
Enumeraciones fuertemente tipadasParcial
Enumeraciones declaradas por adelantadoNo
AtributosNoNoNo
constexprNoNoNo
AlineaciónTR1ParcialParcial
Constructores de delegaciónNoNo
Constructores de herenciaNoNoNo
Operadores de conversión explícitosNoNo
char16_t/char32_tNoNoNo
Literales de cadena UnicodeNoNoNo
Literales de cadena sin formatoNoNo
Nombres de carácter universal en literalesNoNoNo
Literales definidos por el usuarioNoNoNo
Tipos de diseño estándar y trivialesNo
Funciones establecidas como valor predeterminado y funciones eliminadasNoNoSí*
Declaraciones friend extendidas
Sizeof extendidoNoNoNo
Espacios de nombres alineadosNoNoNo
Uniones sin restricciónNoNoNo
Tipos locales y sin nombre como argumentos de plantilla
Bucle for basado en intervaloNo
override y final v0.8, v0.9, v1.0Parcial
Compatibilidad mínima con GC
noexceptNoNoNo

[En este artículo]

Tabla de características principales del lenguaje C++11: simultaneidad

Características principales del lenguaje C++11: simultaneidadVisual Studio 2010Visual Studio 2012Visual Studio 2013Visual Studio 2015
Puntos de secuencia modificadosN/DN/DN/D
Tipos atómicosNo
Comparación e intercambio segurosNo
Barreras bidireccionalesNo
Modelo de memoriaN/DN/DN/D
Ordenación de dependencia de datosNo
Ordenación de dependencia de datos: anotación de funciónNoNoNo
exception_ptr
quick_exitNoNoNo
Tipos atómicos en controladores de señalNoNoNoNo
Almacenamiento local de subprocesosParcialParcialParcial
Estática mágicaNoNoNo

[En este artículo]

Características principales del lenguaje C++11: C99

Características principales del lenguaje C++11: C99Visual Studio 2010Visual Studio 2012Visual Studio 2013Visual Studio 2015
__func__ParcialParcialParcial
Preprocesador C99ParcialParcialParcialParcial
long long
Tipos enteros extendidosN/DN/DN/DN/D

[En este artículo]

Características principales del lenguaje C++14

CaracterísticaVisual Studio 2013Visual Studio 2015
Funcionamiento modificado para conversiones contextuales
Literales binariosNo
Tipos devueltos auto y decltype(auto)No
init-captureNo
Lambdas genéricasNo
Plantillas de variablesNoNo
constexpr extendidoNoNo
NSDMI para agregadosNoNo
Evitar/fusionar asignacionesNoNo
atributos [[deprecated]]NoNo
Asignación con tamañoNo
Separadores de dígitosNo

Características principales propuestas del lenguaje C++17

CaracterísticaVisual Studio 2013Visual Studio 2015
Nuevas reglas para auto con listas de inicialización entre llavesNoNo
assert estático breveNoNo
typename en parámetros de plantilla de la plantillaNoNo
Eliminación de trígrafos
Definiciones de espacio de nombres anidadasNoNo
N4259 std::uncaught_exceptions()NoNo
N4261 Corregir conversiones de cualificaciónNoNo
N4266 Atributos de espacios de nombres y enumeradoresNoNo
N4267 Literales de caracteres de u8NoNo
N4268 Permitir más argumentos de plantilla sin tipoNoNo
N4295 Expresiones plegadasNoNo
await/resumeNo

Referencias a valor R

System_CAPS_ICON_note.jpg Nota

Las designaciones de versión (v0.1, v1.0, v2.0, v2.1, v3.0) de las siguientes descripciones se han concebido únicamente para mostrar la evolución de C++11. El propio estándar no las usa.

El artículo N1610 sobre la aclaración de inicialización de objetos de clase por los valores R fue un intento temprano de habilitar la semántica de movimiento sin referencias a valor R. Para simplificar el debate, lo hemos denominado "Referencias a valor R v0.1". Se reemplazó por "Referencias a valor R v1.0". En "Referencias a valor R v2.0", que es el trabajo en el que se basó Visual C++ en Visual Studio 2010, se prohíbe que las referencias a valor R se enlacen a valores L y, por tanto, se corrige un problema de seguridad importante. En "Referencias a valor R v2.1" se refina esta regla. Considere vector<string>::push_back(), que tiene las sobrecargas push_back(const string&) y push_back(string&&), y la llamada v.push_back("strval"). La expresión "strval" es un literal de cadena y es un valor L. (Otros literales son valores R, por ejemplo el entero 1729, pero los literales de cadena son especiales porque son matrices). Las reglas de "Referencias a valor R v2.0" establecían que string&& no se puede enlazar a "strval" porque "strval" es un valor L y, por consiguiente, push_back(const string&) es la única sobrecarga viable. Esto crearía una clase std::string temporal, la copiaría en el vector y, a continuación, destruiría la std::string temporal, lo que no era muy eficiente. Las reglas de "Referencias a valor R v2.1" reconocen que enlazar string&& a "strval" crearía una clase std::string temporal, que es un valor R. Por consiguiente, push_back(const string&) y push_back(string&&) son viables, y se prefiere push_back(string&&). Se construye una clase std::string temporal y después se mueve al vector. Esto es más eficaz.

En "Referencias a valor R v3.0" se agregan nuevas reglas para generar automáticamente constructores de movimiento y mover los operadores de asignación en determinadas condiciones. Esto se implementa en Visual Studio 2015.

[En este artículo]

Lambdas

Después de que se votaran las funciones lambda en el documento de trabajo (versión "0.9") y se agregaran las expresiones lambda mutables (versión "1.0"), el comité de estandarización revisó el texto. Esto generaba expresiones lambda versión "1.1", que ahora son totalmente compatibles. El texto de las expresiones lambda v1.1 explica lo que debe ocurrir en los casos extremos, como los referentes a miembros estáticos o expresiones lambda anidadas. Esto corrige los problemas que las expresiones lambda complejas producían. Además, las expresiones lambda sin estado se pueden convertir ahora en punteros de función. Esto no está en el texto de N2927, pero se cuenta como parte de las expresiones lambda v1.1 de todos modos.C++11 5.1.2 [expr.prim.lambda]/6 tiene una descripción similar a la siguiente: "El tipo de cierre de una lambda-expression sin lambda-capture tiene una función de conversión const pública no explícita ni virtual para el puntero a función con los mismos tipos devueltos y de parámetro que el operador de llamada de función del tipo de cierre. El valor devuelto por esta función de conversión será la dirección de una función que, cuando se invoca, tiene el mismo efecto que invocar el operador de llamada de función del tipo de cierre". (La implementación de Visual C++ en Visual Studio 2012 es incluso mejor que esta, dado que hace que las expresiones lambda sin estado se puedan convertir a punteros de función que tienen convenciones de llamada arbitrarias. Esto es importante cuando se utilizan API que esperan elementos como los punteros de función __stdcall).

[En este artículo]

decltype

Después de que se votara decltype en el documento de trabajo (versión 1.0), recibió a última hora una corrección pequeña pero importante (versión 1.1). Esto es de gran interés para los programadores que trabajan en STL y Boost.

[En este artículo]

Enumeraciones fuertemente tipadas y declaradas por adelantado

Las enumeraciones fuertemente tipadas se admiten parcialmente para Visual C++ en Visual Studio 2010 (específicamente, la parte sobre los tipos subyacentes especificados explícitamente). Ahora están completamente implementadas en Visual Studio y la semántica de C++11 para las enumeraciones declaradas por adelantado también está totalmente implementada.

[En este artículo]

Alineación

Las palabras clave del lenguaje principal alignas/alignof de la propuesta de alineación que se votó en el documento de trabajo están implementadas Visual Studio 2015. Visual C++ en Visual Studio 2010 incluía aligned_storage a partir de TR1. En Visual C++ en Visual Studio 2012 se agregaron aligned_union y std::align() a la biblioteca estándar y se corrigieron problemas significativos en Visual C++ en Visual Studio 2013.

[En este artículo]

Tipos de diseño estándar y triviales

Los cambios expuestos en el artículo N2342 sobre la revisión de POD para resolver el problema principal 568 (revisión 5) son las incorporaciones de is_trivial e is_standard_layout en <type_traits> de la Biblioteca de plantillas estándar. (En N2342 se modificó una gran parte del texto del lenguaje principal, pero no son necesarios cambios del compilador). Estos rasgos de tipo estaban disponibles para Visual C++ en Visual Studio 2010, pero simplemente han duplicado is_pod. Por consiguiente, en la tabla anterior de este documento la compatibilidad es "No". Ahora usan la tecnología de los enlaces de compilador que se han diseñado para dar respuestas exactas.

common_type<> de la STL recibió una corrección muy necesaria en Visual C++ en Visual Studio 2013. La especificación de C++11 para common_type<> tuvo consecuencias inesperadas no deseadas; concretamente, hace que common_type<int, int>::type devuelva int&&. Por consiguiente, Visual C++ en Visual Studio 2013 implementa la resolución propuesta para el problema 2141 del grupo de trabajo de biblioteca, que hace que common_type<int, int>::type devuelva int.

Un efecto secundario de este cambio es que ya no funciona el caso de identidad (common_type<T> no siempre devuelve un tipo T). Este comportamiento se ajusta a la resolución propuesta, pero interrumpe cualquier código que dependiera del comportamiento anterior.

Si necesita un tipo de rasgo de identidad, no utilice la clase std::identity no estándar que se define en <type_traits> porque no funcionará para <void>. En su lugar, implemente un rasgo de tipo de identidad propio que se ajuste a sus necesidades. Por ejemplo:

template <typename T> struct Identity { typedef T type; };  
  

System_CAPS_ICON_note.jpg Nota

Para conocer otros cambios importantes, vea Cambios importantes en Visual C++ 2015.

[En este artículo]

Funciones establecidas como valor predeterminado y funciones eliminadas

Estos se admiten ahora, pero con esta excepción: para las funciones establecidas de forma predeterminada, no se admite el uso de =default para solicitar constructores de movimiento y operadores de asignación de movimiento miembro a miembro. Las copias y los movimientos no interactúan con precisión como se indica en el estándar; por ejemplo, se especifica que la eliminación de movimientos debe suprimir también las copias, pero Visual C++ en Visual Studio 2013 no las elimina.

Para obtener información sobre cómo usar las funciones establecidas como valor predeterminado y las funciones eliminadas, vea Funciones.

[En este artículo]

override y final

Estas palabras clave han tenido una evolución corta pero complicada. Originalmente, la versión 0.8, tenía los atributos [[override]], [[hiding]] y [[base_check]]. Posteriormente, en la versión 0.9, los atributos se eliminaron y se reemplazaron por palabras clave contextuales. Por último, en la versión 1.0, se redujeron a "final" en las clases y a "override" y "final" en las funciones. Esto crea una extensión ascendida, porque Visual C++ en Visual Studio 2010 ya admitía esta sintaxis de "override" en las funciones y tenía una semántica bastante parecida a la de C++11. "final" también se admite, pero con una ortografía diferente "sellada". La ortografía y la semántica estándar de "override" y "final" se admiten ahora por completo. Para obtener más información, consulte override (especificador) y final (especificador).

[En este artículo]

Tipos atómicos y más

Los tipos atómicos, la comparación e intercambio seguros, las barreras bidireccionales y la ordenación de dependencia de datos especifican la maquinaria de la biblioteca estándar que se implementa ahora.

Encabezados de STL relacionados: <atomic>, <chrono>, <condition_variable>, <future>, <mutex>, <ratio>, <scoped_allocator> y <thread>.

[En este artículo]

__func__ y reglas de preprocesador de C99

En la tabla Características principales del lenguaje C++11: C99 hay dos elementos para los que figura una implementación "Parcial". En el caso del identificador predefinido __func__, "Parcial" aparece porque existe compatibilidad con las extensiones no estándar __FUNCDNAME__, __FUNCSIG__ y __FUNCTION__. Para obtener más información, vea Macros predefinidas. En el caso de las reglas de preprocesador de C99, "Parcial" se muestra porque se admiten macros variádicas. Para obtener más información, vea Macros variádicas.

[En este artículo]

Características de la biblioteca estándar

Esto cubre el lenguaje principal. En cuanto a la biblioteca estándar de C++11, no tenemos una tabla de características comparadas, pero Visual C++ en Visual Studio 2012 la implementa, con dos excepciones. Primero, cuando una característica de biblioteca dependía de una funcionalidad que faltaba en el compilador, se simulaba (por ejemplo, las plantillas variádicas simuladas para make_shared<T>()) o no se implementaba. (Hay solo unos pocos casos, el más notable de los cuales es <initializer_list>, que estuvieran completamente implementados en Visual C++ en Visual Studio 2013). Con muy pocas excepciones, C99 se ha implementado en los encabezados de contenedor de Visual C++ en Visual Studio 2013 y C++ proporcionados. Para obtener más información, vea Compatibilidad con bibliotecas de C99 en Visual Studio 2013.

A continuación se muestra una lista parcial de los cambios en Visual C++ en Visual Studio 2012 y Visual C++ en Visual Studio 2013:

Emplazamiento: tal como lo requiere C++11, emplace()/emplace_front()/emplace_back()/emplace_hint()/emplace_after() se implementan en todos los contenedores para los números de argumentos "arbitrarios" (vea la sección "Plantillas variádicas simuladas"). Por ejemplo, vector<T> incluye "template <typename... Args> void emplace_back(Args&&... args)", que construye directamente un elemento de tipo T al final del vector de un número arbitrario de argumentos arbitrarios, reenviados perfectamente. Esto puede ser más eficaz que push_back(T&&), que implicaría una construcción y una destrucción de movimiento adicionales.

Plantillas variádicas: Visual C++ en Visual Studio 2012 tenía un esquema para simular plantillas variádicas. En Visual C++ en Visual Studio 2013, no aparecen las simulaciones y las plantillas variádicas están totalmente implementadas. Si el código depende del comportamiento anterior de las plantillas variádicas simuladas, tiene que corregirlo. Sin embargo, el cambio a las plantillas variádicas verdaderas tiene mejores tiempos de compilación y menor consumo de memoria del compilador.

Operadores de conversión explícitos: en el lenguaje principal, los operadores de conversión explícitos son una característica general, por ejemplo, se puede usar explicit operator MyClass(). Sin embargo, la biblioteca estándar utiliza actualmente un único formato: explicit operator bool(), que crea clases seguras de pruebas booleanas. ("operator bool()", por sí solo, es notablemente peligroso). Previamente, Visual C++ simulaba explicit operator bool() con operator pointer-to-member(), que produjo más de un dolor de cabeza y leves ineficiencias. Ahora, esta solución de "falsa comprobación booleana" se ha quitado por completo.

Aleatoriedad: uniform_int_distribution es absolutamente imparcial ahora y shuffle() está implementado en <algorithm>, que acepta directamente los generadores de número aleatorio uniforme como mersenne_twister.

Resistencia a los operadores address-of sobrecargados: C++98/03 prohibía que un elemento de un contenedor STL sobrecargara su operador address-of. Esto es lo que hacen las clases como CComPtr, de modo que las clases auxiliares como CAdapt eran necesarias para proteger STL de estas sobrecargas. Durante el desarrollo de Visual C++ en Visual Studio 2010, los cambios en STL hacían que rechazara operadores address-of sobrecargados incluso en más situaciones. C++11 cambió los requisitos para que los operadores address-of sobrecargados sean aceptables. C++11 y Visual C++ en Visual Studio 2010 proporcionan la función auxiliar std::addressof(), que puede obtener la dirección real de un objeto independientemente de la sobrecarga de operadores. Antes del lanzamiento de Visual C++ en Visual Studio 2010, intentamos reemplazar las apariciones de "&elem" por "std::addressof(elem)", que es adecuadamente resistente.Visual C++ en Visual Studio 2012 fue más allá, así que las clases que sobrecargan su operador address-of se deben poder usar siempre en STL.

Visual C++ en Visual Studio 2012 fue más allá de C++11 de varias maneras:

Iteradores SCARY: debido a que se permiten pero no se requieren en el estándar C++11, los iteradores SCARY se han implementado, tal como se describe en los artículos N2911 sobre la minimización de dependencias dentro de las clases genéricas para programas más rápidos y más pequeños y N2980 sobre la asignación e inicialización del iterador SCARY, revisión 1.

Filesystem: se agregó el encabezado <filesystem> de la propuesta TR2. Proporciona recursive_directory_iterator y otras características interesantes. Antes de que el trabajo en TR2 se inmovilizara porque C++0x iba muy lento y se cambiara a C++11, la propuesta de 2006 se derivó de Boost.Filesystem V2. Posteriormente se convirtió en Boost.Filesystem V3, que se implementó en Visual Studio 2015.

Y además una optimización importante. Todos los contenedores son ahora óptimamente pequeños dadas sus representaciones actuales. Esto hace referencia a los propios objetos contenedores, no a los contenidos a los que señala. Por ejemplo, std::vector contiene tres punteros sin formato. Para Visual C++ en Visual Studio 2010, el modo de versión x86, std::vector era de 16 bytes. Para Visual C++ en Visual Studio 2012, es de 12 bytes, que es óptimamente pequeño. Esto es importante: si hay 100 000 vectores en el programa, Visual C++ en Visual Studio 2012 ahorra 400 000 bytes. Un menor uso de memoria ahorra espacio y tiempo.

Esto se logra al evitar el almacenamiento de asignadores y comparadores vacíos, porque std::allocator y std::less no tienen estado. (Estas optimizaciones también se habilitan para los asignadores o comparadores personalizados, siempre que estén sin estado. Naturalmente, el almacenamiento de asignadores y comparadores con estado no se puede evitar, pero solo en casos poco frecuentes).

Visual C++ en Visual Studio 2013 implementa algunas características clave de la biblioteca de C++14:

  • “Objetos functor de operador transparentes” less<>, greater<>, plus<>, multiplies<>, etc.

  • make_unique<T>(args...) y make_unique<T[]>(n)

  • Funciones no miembro cbegin()/cend(), rbegin()/rend() y crbegin()/crend().

[En este artículo]

Aquí está otra vez C++
Referencia de lenguaje C++
Expresiones lambda
Instrucción for basada en intervalo (C++)
Biblioteca estándar de C++
Blog del equipo de Visual C++
Novedades de Visual C++
Cambios importantes en Visual C++ 2015

Mostrar: