[c++] ¿Puede el código C ++ ser válido tanto en C ++ 03 como en C ++ 11 pero hacer cosas diferentes?


Answers

Le señalo gustedt.wordpress.com/2013/12/15/… y el seguimiento , que tiene un buen ejemplo de cómo >> puede cambiar el significado de C ++ 03 a C ++ 11 mientras se sigue compilando 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 en main , que es una expresión.

En C ++ 03:

1 >> ::three = 0
=> fon< fun< 0 >::two >::one;

fun< 0 >::two = int
=> fon< int >::one

fon< int >::one = true
=> true

En C ++ 11

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 sí presentó una advertencia de Clang cuando lo probé.

Question

¿Es posible que el código C ++ cumpla tanto con el estándar C++03 estándar C++11 , pero haga cosas diferentes dependiendo de bajo qué estándar se está compilando?




Un cambio retrocompatible potencialmente peligroso es en los constructores de contenedores de secuencia como std::vector , específicamente en la sobrecarga que especifica el tamaño inicial. Donde en C ++ 03, copiaron un elemento construido por defecto, en C ++ 11 construyen 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';
}

C ++ 03 Ejemplo en vivo

C ++ 11 Ejemplo en vivo

La razón es que C ++ 03 especificó una sobrecarga para "especificar el tamaño y el elemento prototipo" y "especificar solo el tamaño", así (los argumentos del asignador se omiten por brevedad):

container(size_type size, const value_type &prototype = value_type());

Esto siempre copiará el prototype en el size del contenedor veces. Cuando se le llama con un solo argumento, creará copias de size de un elemento construido por defecto.

En C ++ 11, esta firma de constructor fue eliminada y reemplazada por estas dos sobrecargas:

container(size_type size);

container(size_type size, const value_type &prototype);

El segundo funciona como antes, creando copias de size del elemento prototype . Sin embargo, el primero (que ahora maneja las llamadas con solo el argumento de tamaño especificado) predetermina: construye cada elemento individualmente.

Supongo que el motivo 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, y rara vez documentado.




Este hilo Qué diferencias, si las hay, entre C ++ 03 y C ++ 0x que se pueden detectar en el tiempo de ejecución tiene ejemplos (copiados de ese hilo) para determinar las diferencias de idioma, por ejemplo explotando el colapso de referencia 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);
}



Links