¿Es posible que el código C ++ cumpla tanto con el estándar C ++ 03 como con el estándar C ++ 11 , pero hacer cosas diferentes según bajo qué estándar se esté compilando?
La respuesta es un sí rotundo. En el lado positivo hay:
En el lado negativo, se enumeran varios ejemplos en el apéndice C de la norma. Aunque hay muchos más negativos que positivos, cada uno de ellos es mucho menos probable que ocurra.
Literales de cadena
#define u8 "abc"
const char* s = u8"def"; // Previously "abcdef", now "def"
y
#define _x "there"
"hello "_x // Previously "hello there", now a user defined string literal
Tipo de conversiones de 0
En C ++ 11, solo los literales son constantes de puntero nulo enteros:
void f(void *); // #1
void f(...); // #2
template<int N> void g() {
f(0*N); // Calls #2; used to call #1
}
Resultados redondeados después de la división de enteros y el módulo
En C ++ 03 se permitió al compilador redondear hacia 0 o hacia el infinito negativo. En C ++ 11 es obligatorio redondear hacia 0
int i = (-1) / 2; // Might have been -1 in C++03, is now ensured to be 0
Espacios en blanco entre llaves de cierre de plantilla anidadas >> vs>>
Dentro de una especialización o instanciación >>
, en cambio, podría interpretarse como un desplazamiento a la derecha en C ++ 03. Sin embargo, es más probable que esto rompa el código existente: (de http://gustedt.wordpress.com/2013/12/15/a-disimprovement-observed-from-the-outside-right-angle-brackets/ )
template< unsigned len > unsigned int fun(unsigned int x);
typedef unsigned int (*fun_t)(unsigned int);
template< fun_t f > unsigned int fon(unsigned int x);
void total(void) {
// fon<fun<9> >(1) >> 2 in both standards
unsigned int A = fon< fun< 9 > >(1) >>(2);
// fon<fun<4> >(2) in C++03
// Compile time error in C++11
unsigned int B = fon< fun< 9 >>(1) > >(2);
}
El operador new
ahora puede lanzar otras excepciones questd::bad_alloc
struct foo { void *operator new(size_t x){ throw std::exception(); } }
try {
foo *f = new foo();
} catch (std::bad_alloc &) {
// c++03 code
} catch (std::exception &) {
// c++11 code
}
Los destructores declarados por el usuario tienen un ejemplo de especificación de excepción implícita de ¿Qué cambios importantes se introducen en C ++ 11?
struct A {
~A() { throw "foo"; } // Calls std::terminate in C++11
};
//...
try {
A a;
} catch(...) {
// C++03 will catch the exception
}
size()
de contenedores ahora se requiere para funcionar en O (1)
std::list<double> list;
// ...
size_t s = list.size(); // Might be an O(n) operation in C++03
std::ios_base::failure
no deriva directamente de std::exception
más
Si bien la clase base directa es nueva, std::runtime_error
no lo es. Así:
try {
std::cin >> variable; // exceptions enabled, and error here
} catch(std::runtime_error &) {
std::cerr << "C++11\n";
} catch(std::ios_base::failure &) {
std::cerr << "Pre-C++11\n";
}
Le señalo este artículo y el seguimiento , que tiene un buen ejemplo de cómo se >>
puede cambiar el significado de C ++ 03 a C ++ 11 mientras se compila en ambos.
bool const one = true;
int const two = 2;
int const three = 3;
template<int> struct fun {
typedef int two;
};
template<class T> struct fon {
static int const three = ::three;
static bool const one = ::one;
};
int main(void) {
fon< fun< 1 >>::three >::two >::one; // valid for both
}
La parte clave es la línea in main
, que es una expresión.
1 >> ::three = 0
=> fon< fun< 0 >::two >::one;
fun< 0 >::two = int
=> fon< int >::one
fon< int >::one = true
=> true
fun< 1 > is a type argument to fon
fon< fun<1> >::three = 3
=> 3 > ::two > ::one
::two is 2 and ::one is 1
=> 3 > 2 > 1
=> (3 > 2) > 1
=> true > 1
=> 1 > 1
=> false
Felicitaciones, dos resultados diferentes para la misma expresión. Por supuesto, el C ++ 03 presentó un formulario de advertencia Clang cuando lo probé.
Sí, hay varios cambios que harán que el mismo código dé como resultado un comportamiento diferente entre C ++ 03 y C ++ 11. Las diferencias en las reglas de secuenciación provocan algunos cambios interesantes, incluido un comportamiento previamente indefinido que se vuelve bien definido.
1. múltiples mutaciones de la misma variable dentro de una lista de inicializadores
Un caso de esquina muy interesante sería múltiples mutaciones de la misma variable dentro de una lista de inicializador, por ejemplo:
int main()
{
int count = 0 ;
int arrInt[2] = { count++, count++ } ;
return 0 ;
}
Tanto en C ++ 03 como en C ++ 11 esto está bien definido, pero el ¿Hay múltiples mutaciones de la misma variable dentro de las listas de inicializadores comportamiento indefinido antes de C ++ 11? pero en ¿Las mutaciones múltiples dentro de las listas de inicializadores tienen un comportamiento indefinido? . Entonces, si compilamos usando clang
en modo C ++ 03, brinda la siguiente advertencia ( véalo en vivo ):
warning: multiple unsequenced modifications to 'count' [-Wunsequenced]
int arrInt[2] = { count++, count++ } ;
^ ~~
pero no proporciona una advertencia en C ++ 11 ( verlo en vivo ).
2. Las nuevas reglas de secuenciación hacen que i = ++ i + 1; bien definido en C ++ 11
Las nuevas reglas de secuenciación adoptadas después de C ++ 03 significan que:
int i = 0 ;
i = ++ i + 1;
ya no es un comportamiento indefinido en C ++ 11, esto se trata en el informe de defectos 637. Las reglas de secuenciación y el ejemplo no están de acuerdo
3. Las nuevas reglas de secuenciación también hacen ++++ i; bien definido en C ++ 11
Las nuevas reglas de secuenciación adoptadas después de C ++ 03 significan que:
int i = 0 ;
++++i ;
ya no es un comportamiento indefinido en C ++ 11.
4. Desplazamientos a la izquierda firmados un poco más sensatos
Los borradores posteriores de C ++ 11 incluyen los N3485
que enlazo a continuación y corrigieron el comportamiento indefinido de cambiar un bit 1 dentro o más allá del bit de signo . Esto también se trata en el informe de defectos 1457 . Howard Hinnant comentó sobre la importancia de este cambio en el hilo de ¿Es el desplazamiento a la izquierda (<<) un comportamiento indefinido de entero negativo en C ++ 11?.
5. Las funciones constexpr se pueden tratar como expresiones constantes de tiempo de compilación en C ++ 11
C ++ 11 introdujo funciones constexpr que:
El especificador constexpr declara que es posible evaluar el valor de la función o variable en tiempo de compilación. Estas variables y funciones se pueden utilizar cuando solo se permiten expresiones de constantes de tiempo de compilación.
mientras que C ++ 03 no tiene la característica constexpr , no tenemos que usar explícitamente la palabra clave constexpr ya que la biblioteca estándar proporciona muchas funciones en C ++ 11 como constexpr . Por ejemplo, std :: numeric_limits :: min . Lo que puede llevar a comportamientos diferentes, por ejemplo:
#include <limits>
int main()
{
int x[std::numeric_limits<unsigned int>::min()+2] ;
}
Si se usa clang
en C ++ 03, esto hará x
que sea una matriz de longitud variable, que es una extensión y generará la siguiente advertencia:
warning: variable length arrays are a C99 feature [-Wvla-extension]
int x[std::numeric_limits<unsigned int>::min()+2] ;
^
mientras que en C ++ 11 std::numeric_limits<unsigned int>::min()+2
es una expresión constante de tiempo de compilación y no requiere la extensión VLA.
6. En C ++ 11, no se generan implícitamente especificaciones de excepción para sus destructores
Dado que en C ++ 11 el destructor definido por el usuario tiene una noexcept(true)
especificación implícita como se explica en noexcept destructors , significa que el siguiente programa:
#include <iostream>
#include <stdexcept>
struct S
{
~S() { throw std::runtime_error(""); } // bad, but acceptable
};
int main()
{
try { S s; }
catch (...) {
std::cerr << "exception occurred";
}
std::cout << "success";
}
En C ++ 11 llamará std::terminate
pero se ejecutará correctamente en C ++ 03.
7. En C ++ 03, los argumentos de la plantilla no podían tener vínculos internos.
Esto se explica muy bien en Por qué std :: sort no acepta clases de comparación declaradas dentro de una función . Entonces, el siguiente código no debería funcionar en C ++ 03:
#include <iostream>
#include <vector>
#include <algorithm>
class Comparators
{
public:
bool operator()(int first, int second)
{
return first < second;
}
};
int main()
{
class ComparatorsInner : public Comparators{};
std::vector<int> compares ;
compares.push_back(20) ;
compares.push_back(10) ;
compares.push_back(30) ;
ComparatorsInner comparatorInner;
std::sort(compares.begin(), compares.end(), comparatorInner);
std::vector<int>::iterator it;
for(it = compares.begin(); it != compares.end(); ++it)
{
std::cout << (*it) << std::endl;
}
}
pero actualmente clang
permite este código en modo C ++ 03 con una advertencia a menos que use -pedantic-errors
flag, que es un poco asqueroso, véalo en vivo .
8. >> ya no está mal formado al cerrar varias plantillas
El uso >>
para cerrar varias plantillas ya no está mal formado, pero puede generar un código con resultados diferentes en C ++ 03 y C + 11. El siguiente ejemplo se toma de corchetes en ángulo recto y compatibilidad con versiones anteriores :
#include <iostream>
template<int I> struct X {
static int const c = 2;
};
template<> struct X<0> {
typedef int c;
};
template<typename T> struct Y {
static int const c = 3;
};
static int const c = 4;
int main() {
std::cout << (Y<X<1> >::c >::c>::c) << '\n';
std::cout << (Y<X< 1>>::c >::c>::c) << '\n';
}
y el resultado en C ++ 03 es:
0
3
y en C ++ 11:
0
0
9. C ++ 11 cambia algunos de los constructores std :: vector
El código ligeramente modificado de esta respuesta muestra que el uso del siguiente constructor de std :: vector :
std::vector<T> test(1);
produce diferentes resultados en C ++ 03 y C ++ 11:
#include <iostream>
#include <vector>
struct T
{
bool flag;
T() : flag(false) {}
T(const T&) : flag(true) {}
};
int main()
{
std::vector<T> test(1);
bool is_cpp11 = !test[0].flag;
std::cout << is_cpp11 << std::endl ;
}
10. Reducción de conversiones en inicializadores agregados
En C ++ 11, una conversión de restricción en inicializadores agregados está mal formada y parece que gcc
permite esto tanto en C ++ 11 como en C ++ 03, aunque proporciona una advertencia de forma predeterminada en C ++ 11:
int x[] = { 2.0 };
Esto se trata en el párrafo 3 de 8.5.4
Inicialización de lista de la sección estándar de C ++ 11 :
La inicialización de lista de un objeto o referencia de tipo T se define como sigue:
y contiene la siguiente viñeta (el énfasis es mío ):
De lo contrario, si T es un tipo de clase, se consideran los constructores. Se enumeran los constructores aplicables y se elige el mejor mediante resolución de sobrecarga (13.3, 13.3.1.7). Si se requiere una conversión de restricción (ver más abajo) para convertir cualquiera de los argumentos, el programa está mal formado
Esta y muchas más instancias se tratan en la sección del borrador del estándar annex C.2
C ++ C ++ e ISO C ++ 2003 . También incluye:
Nuevos tipos de literales de cadena [...] Específicamente, las macros denominadas R, u8, u8R, u, uR, U, UR o LR no se expandirán cuando estén adyacentes a un literal de cadena, pero se interpretarán como parte del literal de cadena . Por ejemplo
#define u8 "abc"
const char *s = u8"def"; // Previously "abcdef", now "def"
Soporte de cadenas literales definidas por el usuario [...] Anteriormente, el # 1 habría consistido en dos tokens de preprocesamiento separados y la macro _x se habría expandido. En esta Norma Internacional, el n. ° 1 consta de un solo token de preprocesamiento, por lo que la macro no se expande.
#define _x "there"
"hello"_x // #1
Especificar el redondeo para los resultados del código entero / y% [...] 2003 que usa división de enteros redondea el resultado hacia 0 o hacia el infinito negativo, mientras que esta Norma Internacional siempre redondea el resultado hacia 0.
La complejidad de las funciones de los miembros size () ahora es constante [...] Algunas implementaciones de contenedores que cumplen con C ++ 2003 pueden no cumplir con los requisitos de size () especificados en esta Norma Internacional. El ajuste de contenedores como std :: list a los requisitos más estrictos puede requerir cambios incompatibles.
Cambiar la clase base de std :: ios_base :: failure [...] std :: ios_base :: failure ya no se deriva directamente de std :: exception, sino que ahora se deriva de std :: system_error, que a su vez se deriva de std :: runtime_error. El código C ++ 2003 válido que asume que std :: ios_base :: failure se deriva directamente de std :: exception puede ejecutarse de manera diferente en esta Norma Internacional.
Un cambio potencialmente peligroso e incompatible con versiones anteriores es en los constructores de contenedores de secuencia como std::vector
, específicamente, en la sobrecarga que especifica el tamaño inicial. Mientras que en C ++ 03, copiaron un elemento construido por defecto, en C ++ 11 construyeron por defecto cada uno.
Considere este ejemplo (usando boost::shared_ptr
para que sea válido C ++ 03):
#include <deque>
#include <iostream>
#include "boost/shared_ptr.hpp"
struct Widget
{
boost::shared_ptr<int> p;
Widget() : p(new int(42)) {}
};
int main()
{
std::deque<Widget> d(10);
for (size_t i = 0; i < d.size(); ++i)
std::cout << "d[" << i << "] : " << d[i].p.use_count() << '\n';
}
La razón es que C ++ 03 especificó una sobrecarga para "especificar tamaño y elemento de prototipo" y "especificar tamaño solamente", así (los argumentos del asignador se omiten por brevedad):
container(size_type size, const value_type &prototype = value_type());
Esto siempre se copiará prototype
en los size
tiempos del contenedor . Cuando se llama con un solo argumento, creará size
copias de un elemento construido por defecto.
En C ++ 11, esta firma de constructor se eliminó y se reemplazó con estas dos sobrecargas:
container(size_type size);
container(size_type size, const value_type &prototype);
El segundo funciona como antes, creando size
copias del prototype
elemento. Sin embargo, el primero (que ahora maneja llamadas con solo el argumento de tamaño especificado) construye por defecto cada elemento individualmente.
Supongo que la razón de este cambio es que la sobrecarga de C ++ 03 no se podría usar con un tipo de elemento de solo movimiento. Pero es un cambio radical, no obstante, y rara vez se documenta en eso.
El resultado de una lectura fallida de un std::istream
ha cambiado. CppReference lo resume muy bien:
Si la extracción falla (por ejemplo, si se ingresó una letra donde se esperaba un dígito),
value
se deja sin modificar yfailbit
se establece. (hasta C ++ 11)Si la extracción falla, se escribe cero
value
yfailbit
se establece. Si la extracción da como resultado un valor demasiado grande o demasiado pequeño para cabervalue
,std::numeric_limits<T>::max()
ostd::numeric_limits<T>::min()
se escribe yfailbit
se establece el indicador. (desde C ++ 11)
Esto es principalmente un problema si está acostumbrado a la nueva semántica y luego tiene que escribir usando C ++ 03. Lo siguiente no es una práctica particularmente buena, pero está bien definida en C ++ 11:
int x, y;
std::cin >> x >> y;
std::cout << x + y;
Sin embargo, en C ++ 03, el código anterior usa una variable no inicializada y por lo tanto tiene un comportamiento indefinido.
Este hilo ¿Qué diferencias, si las hay, entre C ++ 03 y C ++ 0x se pueden detectar en tiempo de ejecución? Tiene ejemplos (copiados de ese hilo) para determinar las diferencias de idioma, por ejemplo, aprovechando el colapso de referencias de C ++ 11:
template <class T> bool f(T&) {return true; }
template <class T> bool f(...){return false;}
bool isCpp11()
{
int v = 1;
return f<int&>(v);
}
y c ++ 11 que permite tipos locales como parámetros de plantilla:
template <class T> bool cpp11(T) {return true;} //T cannot be a local type in C++03
bool cpp11(...){return false;}
bool isCpp0x()
{
struct local {} var; //variable with local type
return cpp11(var);
}
Aquí hay otro ejemplo:
#include <iostream>
template<class T>
struct has {
typedef char yes;
typedef yes (&no)[2];
template<int> struct foo;
template<class U> static yes test(foo<U::bar>*);
template<class U> static no test(...);
static bool const value = sizeof(test<T>(0)) == sizeof(yes);
};
enum foo { bar };
int main()
{
std::cout << (has<foo>::value ? "yes" : "no") << std::endl;
}
Huellas dactilares:
Using c++03: no
Using c++11: yes
La estrella de HGTV, Christina Hall, revela que le diagnosticaron envenenamiento por mercurio y plomo, probablemente debido a su trabajo como manipuladora de casas.
Recientemente salió a la luz un informe policial que acusa a la estrella de 'Love Is Blind', Brennon, de violencia doméstica. Ahora, Brennon ha respondido a los reclamos.
Conozca cómo Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia mientras organizaba la primera celebración de Acción de Gracias desde que murió su madre, Naomi Judd.
Descubra por qué un destacado experto en lenguaje corporal cree que es fácil trazar "tales paralelismos" entre la princesa Kate Middleton y la princesa Diana.
Los inodoros arrojan columnas de aerosol invisibles con cada descarga. ¿Como sabemos? La prueba fue capturada por láseres de alta potencia.
Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?
The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!
¿Sigue siendo efectivo ese lote de repelente de insectos que te quedó del verano pasado? Si es así, ¿por cuánto tiempo?
Si este tráiler de pesadilla de la temporada más reciente de Great British Bake Off te asustó y te hizo no volver a ver el programa, es posible que tengas suerte: PBS no ha decidido si se transmitirá o no la última temporada en los Estados Unidos. actualización, para aquellos que no siguen sin aliento este tipo de drama de nicho: el presentador Paul Hollywood y la hermosa carpa llena de batidoras de colores pastel y cuadros se trasladaron de la BBC al Canal 4; Mary Berry, Sue Perkins y Mel Giedroyc renunciaron.
Foto: Netflix Oh, Hello On Broadway (Netflix): Después de llegar a Broadway el año pasado, los dos locos del Upper West Side interpretados por John Mulaney y Nick Kroll finalmente llegaron a Netflix. El especial consta del espectáculo en el escenario, algunos momentos entre bastidores y un invitado muy especial de “Too Much Tuna”.
¿Quiere probar un cepillo de dientes Sonicare sin gastar mucho dinero en uno de sus modelos favoritos de gama alta? Puede comprar un kit de la Serie 2 o Serie 3 por tan solo $ 30 hoy en Amazon. Haga clic aquí para ver la lista completa de modelos elegibles y tenga en cuenta que se descontarán $ 10 adicionales en su carrito.
Tapas elásticas de silicona de Tomorrow's Kitchen, paquete de 12 | $14 | Amazonas | Código promocional 20OFFKINJALids son básicamente los calcetines de la cocina; siempre perdiéndose, dejando contenedores huérfanos que nunca podrán volver a cerrarse. Pero, ¿y si sus tapas pudieran estirarse y adaptarse a todos los recipientes, ollas, sartenes e incluso frutas en rodajas grandes que sobran? Nunca más tendrás que preocuparte por perder esa tapa tan específica.
El equipo está a la espera de las medallas que ganó en los Juegos Olímpicos de Invierno de 2022 en Beijing, ya que se está resolviendo un caso de dopaje que involucra a la patinadora artística rusa Kamila Valieva.
Miles de compradores de Amazon recomiendan la funda de almohada de seda Mulberry, y está a la venta en este momento. La funda de almohada de seda viene en varios colores y ayuda a mantener el cabello suave y la piel clara. Compre las fundas de almohada de seda mientras tienen hasta un 46 por ciento de descuento en Amazon
El jueves se presentó una denuncia de delito menor amenazante agravado contra Joe Mixon.
El Departamento de Policía de Lafayette comenzó a investigar a un profesor de la Universidad de Purdue en diciembre después de recibir varias denuncias de un "hombre sospechoso que se acercaba a una mujer".
Al igual que el mundo que nos rodea, el lenguaje siempre está cambiando. Mientras que en eras anteriores los cambios en el idioma ocurrían durante años o incluso décadas, ahora pueden ocurrir en cuestión de días o incluso horas.
Estoy de vuelta por primera vez en seis años. No puedo decirte cuánto tiempo he estado esperando esto.
“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.
Creo, un poco tarde en la vida, en dar oportunidades a la gente. Generosamente.