Compartir a través de


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

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

En este artículo

  • C++11 Feature List

    • Core Language Feature Table

    • Core Language Feature Table: Concurrency

    • Core Language Feature Table: C99

  • Guide To Feature Tables

    • Rvalue References

    • Lambdas

    • decltype

    • Strongly Typed/Forward Declared enums

    • Alignment

    • Standard-Layout and Trivial Types

    • Defaulted and deleted functions

    • override and final

    • Atomics, and more

    • C99 __func__ and preprocessor rules

  • Standard Library features

Lista de características de C++11

Con Visual C++ en Visual Studio 2010 se implementaron numerosas características en la especificación principal del lenguaje C++11 y, con Visual C++ en Visual Studio 2012, se agregaron más características. Visual C++ en Visual Studio 2013 expande esta cobertura aún más y admite también algunas características de la biblioteca de C++14. En la tabla siguiente se enumeran las características principales del lenguaje C++11 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.

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

Características principales del lenguaje C++11

Visual Studio 2010

Visual Studio 2012

Visual Studio 2013

Referencias a valor R v0.1, v1.0, v2.0, v2.1, v3.0

v2.0

v2.1*

v2.1*

calificadores de referencias

No

No

No

Inicializadores de miembros de datos no estáticos

No

No

Plantillas variádicas v0.9, v1.0

No

No

Listas de inicializadores

No

No

static_assert

auto v0.9, v1.0

v1.0

v1.0

v1.0

Tipos devueltos finales

Lambdas v0.9, v1.0, v1.1

v1.0

v1.1

v1.1

decltype v1.0, v1.1

v1.0

v1.1**

v1.1

Corchetes angulares

Argumentos predeterminados para plantillas de funciones

No

No

Expresión SFINAE

No

No

No

Plantillas de alias

No

No

Plantillas Extern

nullptr

Enumeraciones fuertemente tipadas

Partial

Enumeraciones declaradas por adelantado

No

Atributos

No

No

No

constexpr

No

No

No

Alineación

TR1

Partial

Partial

Delegación de constructores

No

No

Herencia de constructores

No

No

No

Operadores de conversión explícitos

No

No

char16_t/char32_t

No

No

No

Literales de cadena Unicode

No

No

No

Literales de cadena sin formato

No

No

Nombres de caracteres universales en literales

No

No

No

Literales definidos por el usuario

No

No

No

Tipos de diseño estándar y triviales

No

Funciones establecidas como valor predeterminado y eliminadas

No

No

Sí*

Declaraciones friend extendidas

Sizeof extendido

No

No

No

Espacios de nombres alineados

No

No

No

Uniones sin restricción

No

No

No

Tipos locales y sin nombre como argumentos de plantilla

Bucle for basado en intervalo

No

override y final v0.8, v0.9, v1.0

Partial

Compatibilidad mínima GC

noexcept

No

No

No

[go to top]

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

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

Visual Studio 2010

Visual Studio 2012

Visual Studio 2013

Puntos de secuencia modificados

N/D

N/D

N/D

Tipos atómicos

No

Comparación e intercambio seguros

No

Barreras bidireccionales

No

Modelo de memoria

N/D

N/D

N/D

Ordenación de dependencia de datos

No

Ordenación de dependencia de datos: anotación de función

No

No

No

exception_ptr

quick_exit

No

No

No

Tipos atómicos en controladores de señal

No

No

No

Almacenamiento local de subprocesos

Partial

Partial

Partial

Estática mágica

No

No

No

[go to top]

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

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

Visual Studio 2010

Visual Studio 2012

Visual Studio 2013

__func__

Partial

Partial

Partial

Preprocesador C99

Partial

Partial

Partial

long long

Tipos enteros extendidos

N/D

N/D

N/D

[go to top]

Guía para las tablas de características

Referencias a valor R

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 ha reemplazado 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", esta regla se refina. 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. Sin embargo, esto no se implementa en Visual C++ en Visual Studio 2013, debido a restricciones de tiempo y de recursos.

[go to top]

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 puedan convertirse en 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).

[go to top]

decltype

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

[go to top]

Enumeraciones fuertemente tipadas y declaradas por adelantado

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

[go to top]

Alineación

Las palabras clave del lenguaje principal alignas/alignof de la propuesta de alineación que se votó en el documento de trabajo no están implementadas. 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.

[go to top]

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 adiciones de is_trivial e is_standard_layout a <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 tanto, 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;
};

Nota

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

[go to top]

Funciones establecidas como valor predeterminado y funciones eliminadas

Las siguientes funciones son ahora compatibles, con esta salvedad: En el caso de las funciones establecidas como valores predeterminados, no se admite el uso de =default para solicitar constructores de movimiento miembro a miembro y operadores de asignación de movimiento. 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 utilizar las funciones establecidas como valor predeterminado y eliminadas, vea Definiciones de funciones de C++.

[go to top]

override y final

Estas palabras clave han tenido una evolución corta pero complicada. Originalmente, en la versión 0.8, había atributos [[override]], [[hiding]] y [[base_check]]. A continuación, 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, vea override (especificador) y final (especificador).

[go to top]

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>.

[go to top]

__func__ y reglas de preprocesador de C99

En la tabla Core Language Feature Table: C99 hay dos elementos en los que figura una implementación "Partial". En el caso del identificador predefinido __func__, "Partial" 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, "Partial" se muestra porque se admiten macros variádicas. Para obtener más información, vea Macros variádicas.

[go to top]

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 ahora estén 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 más información, consulte la entrada de blog sobre 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: como así lo exige 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 usa 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úmeros aleatorios uniformes 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 deben poders usar a través de 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 y 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 ha agregado 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, se derivó la propuesta 2006 de Boost.Filesystem V2. Posteriormente se convirtió en Boost.Filesystem V3, pero esto no se implementa en Visual C++ en Visual Studio 2012.

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 va aún más allá de C++11 al implementar 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().

[go to top]

Vea también

Referencia

Expresiones lambda en C++

Instrucción for basada en intervalo (C++)

Conceptos

Lo nuevo de Visual C++ en Visual Studio 2013

Cambios importantes en Visual C++

Otros recursos

Aquí está otra vez C++ (C++ moderno)

Referencia de lenguaje C++

Referencia de biblioteca estándar de C++

Blog del equipo de Visual C++