Breve sobre C++11

El C++11, antes conocido como C++0x es el nombre de la más reciente versión de C++, reemplazando al C++03, aprobada por la ISO el día 12 de agosto de 2011. C++11 incluye varias adiciones al núcleo del lenguaje y extiende la biblioteca estándar de C++.

El comité ha aplicado algunas directivas (aplicadas a cada utilidad del nuevo estándar):

  • Mantener la estabilidad y la compatibilidad con el C++98 y posiblemente con C.
  • Preferir la introducción de nuevas características a través de la biblioteca estándar, en lugar de extendiendo el núcleo del lenguaje.
  • Preferir los cambios que puedan hacer evolucionar la técnica de programación.
  • Mejorar el C++ para facilitar el diseño de sistemas y bibliotecas, en vez de introducir nuevas características solamente útiles a aplicaciones específicas.
  • Incrementar la seguridad de os tipos de datos suministrando alternativas más seguras a las técnicas inseguras actuales.
  • Incrementar el rendimiento y la habilidad de trabajar directamente con el hardware.
  • Proveer soluciones apropiadas para los problemas del mundo real.
  • Implementar el principio de zero-overhead (Soporte adicionar requerido por algunas utilidades donde debe ser usado solo si la utilidad es usada).
  • Hacer que C++ sea fácil de enseñar y aprender sin la remoción de cualquier utilidad necesario por los programadores expertos.

Decir que C++11 incluye una serie de cambios que requerirían un artículo (inclusive hasta varios) para dar una explicación exhaustiva de cada una de sus mejoras, me centraré más aún en los que más se evidencian en la nueva versión de Qt (5).

Ahora por fin Qt5

Qt5 viene a ser la próxima entrega de este “Super” Framework para los amantes de C++, incluye nuevas características que lo hacen un poco incompatible con las versiones anteriores como pueden ser:

  • Ahora QWidget es un módulo aparte, pues existe una clase padre de todas las ventanas, la QWindows, esto se implementó para permitir que QML (Lenguaje para descripción de Quick, específicamente para diseño de interfaces) pudiera tomar el control visual de las ventanas principales sin depender de QWidget.
  • El procedimiento de creación de Plugins se ha cambiado en su totalidad.
  • Debido al cambio de versión los módulos y plugins diseñados con Qt 4 no son compatibles con los plugins y módulos diseñados bajo esta nueva versión.

Bien, pero no vengo a dar una explicación exhaustiva de Qt5, ni de C++11, vamos entonces al código, que realmente es lo que nos interesa.

Habilitando el soporte de C++11 en el compilador

Algunos compiladores necesitan una opción en la línea de comandos para habilitar el soporte para C++11. Si usas qmake para construir tus proyectos debes poner en tu .pro, por supuesto esto es para Qt5:

1
CONFIG += c++11

en caso de que queramos habilitarlo utlizando las herramientas de Qt 4 seria:

1
QMAKE_CXXFLAGS += -std=c++11

dichas configuraciones al .pro funcionarían perfectamente para Linux y Windows, en el caso de MacOS, específicamente con la versión de Mac OS X 10.8 y Qt 5.0.2 los usuarios comentan que se debería incluir:

1
2
QMAKE_CXXFLAGS += -std=c++11 -stdlib=libc++ -mmacos-version-min=10.7
LIBS += -stdlib=libc++ -mmacosx-version-min=10.7

En mi caso particular que desarrollo con KDevelop (del cual escribiré un artículo posteriormente) con CMake, para habilitar C++11 sería:

1
add_definitions(--std=c++11)

con estas adiciones, estaríamos compilando nuestro código diciéndole al compilador que estamos utilizando el estándar de C++, C++11.

Iniciadores de listas

La característica nueva de C++11 de inicializar listas nos sería muy útil al inicializar, por ejemplo, un QStringList. En vez de utilizar un código como:

1
2
QStringList frutas;
frutas << "manzana" << "pera" << "tomate";

podría simplificarse con:

1
QStringList frutas { "manzana", "pera", "tomate" };

en el caso de que la variable a inicializar sea un miembro que debe inicializarse en el constructor de la clase, se podría mover la inicialización fuera del bloque del constructor hacia la lista de inicialización del constructor. Por tanto, lo que antes codificábamos así:

1
2
3
4
MiClase::MiClase()
{
    m_frutas << "manzana" << "pera" << "tomate";
}

podemos simplificarlo de esta manera:

1
2
3
4
MiClase::MiClase()
  : m_frutas { "manzana", "pera", "tomate" };
{
}

Ciclos basados en rango

Muchos de nuestros amigos cuando nos hablan de las comparaciones con otros lenguajes, una de las características que siempre nos dicen son los foreach, bueno, ahora C++11 ya implementa estos llamados foreach, aunque Qt implementa una macro foreach, ahora podemos utilizarla de manera nativa, por lo que el código:

1
2
3
4
5
QStringList opciones { "a", "b", "c" };

foreach (const QString &opcion, opciones) {
  std::cout << qPrintable (opcion) << std::endl;
}

puede escribirse usando el nuevo estándar de esta manera:

1
2
3
4
5
QStringList opciones { "a", "b", "c" };

for (const QString &opcion : opciones) {
  std::cout << qPrintable (opcion) << std::endl;
}

Inferencia de tipos

C++11 viene con un nuevo tipo de datos llamado auto, que nos evita tener que poner el tipo de una variable, dejando al compilador que determine su tipo, de manera personal me ha ayudado mucho en la escritura de menos código, por ejemplo, tomando el código anterior, podríamos haberlo escrito de esta manera:

1
2
3
4
5
QStringList opciones { "a", "b", "c" };

for (auto opcion : opciones) {
  std::cout << qPrintable (opcion) << std::endl;
}

ahorrándonos de esa manera tener que poner el tipo completo de opcion. Cuando utilizas el tipo auto también puedes adicionarle los modificadores const y &. auto ha existido desde un principio tanto en C como en C++, pero no era muy útil en su propósito. Su nueva definición permitió que no se tuviera que incluir una nueva palabra clave dentro del lenguaje.

Nuevo estilo de connect()

Las aplicaciones desarrolladas con Qt típicamente hacen un alto uso de signals y slots, los cuales son conectados en tiempo de ejecución usando el método connect. Como estas conecciones son realizadas en tiempo de ejecución es muy fácil cometer errores en los nombre de los argumentos de los signal/slot. Con C++11 tenemos una nueva sintaxis para realizar estas conecciones, que una de las ventajas que trae consigo es la comprobación en tiempo de compilación. Por ejemplo, veamos este viejo estilo de conección:

1
connect (button, SIGNAL(clicked()), checkbox, SLOT(toggle()));

ahora podría escribirse de esta manera:

1
connect (button, &QPushButton::clicked, checkbox, &QCheckBox::toggle);

Con el nuevo estilo de conección, los nombres y argumentos de la signal y el slot son comprobados en tiempo de compilación, evitando que cuando corramos nuestra aplicación es que nos demos cuenta de que la conección está errónea. Otro cambio es que ahora connect en vez de retornar un bool, retorna un QMetaObject::Connection.

C++11 viene con soporte de funciones lambda y Qt 5 le añade soporte a las conecciones para estas funciones, por ejemplo podríamos hacer esto:

1
2
auto mySlot = []() { qDebug() << "Este es mi slot."; }; //Definimos la lambda
connect (button, &QPushButton::clicked, mySlot);        //Y la conectamos

incluso podrías definirla en la misma función de conección, ejemplo:

1
connect (button, &QPushButton::clicked, [=]() { qDebug() << "Este es una funcion lambda"; });

Más específicos de C++11

Constante nullptr

Ahora los punteros nulos deberían igualarse a nullptr y no a 0 o a NULL (es una buena práctica que todos deberíamos ir implementando). Es muy importante aclarar que nullptr no significa 0, sino que es una palabra reservada para determinar punteros nulos. Algunos ejemplos de su uso:

1
2
3
4
char *pc = nullptr;
int  *pi = nullptr;
bool  bp = nullptr; //En este caso la variable se establece en false
int    i = nullptr; //Error, pues no se puede convertir nullptr a int

Angular derecho

A quien no le ha pasado que tiene que separar los angulares derecho en una multidefinición de plantillas, por ejemplo:

1
QList<QMap<QString, int> > list //Si juntamos los >> daría error en C++03

un cambio en las reglas de lenguaje en C++11 ya podemos realizar esto sin que se reporte error alguno:

1
QList<QMap<QString, int>> list //En C++11 no reportaría error alguno

Nuevos literales para las cadenas

Hoy en día los documentos han dejado de utilizar ASCII, por la utilización de Unicode (muy recomendado, por cierto). C++11 no ha quedado exento de ello y ha introducido estos literales nuevos:

1
2
3
4
5
6
7
8
9
QString s1 = "ejemplo";           // Implementación comun
QString s2 = R"(ejemplo\prueba)"; // Cadena `RAW`, no necesita escapar los `backslash`
QString s3 = u8"ejemplo";         // Cadena UTF-8
QString s4 = u8R"(ejemplo)"       // Cadena RAW UTF-8

QString s5 = QString::fromUtf16(reinterpret_cast<const ushort *>(u"ejemplo"));    // Cadena UTF-16
QString s6 = QString::fromUtf16(reinterpret_cast<const ushort *>(uR"(ejemplo)")); // Cadena RAW UTF-16
QString s7 = QString::fromUcs4(reinterpret_cast<const uint *>(U"foo"));           // Cadena  UTF-32
QString s8 = QString::fromUcs4(reinterpret_cast<const uint *>(UR"(foo)"));        // Cadena RAW UTF-32

Tipo long long

Ahora el tipo long long es un estándar y será garantizado su tamaño de 64 bits o mayor, por lo que ya no será necesaria la utilización de qlonglong de Qt.

Concluyendo

Bueno, viendo todas estas características nuevas de C++ y Qt, lo que nos resta es a partir de ahora tenerlas en cuenta para cuando estamos desarrollando nuestros programas. Aquí no están expuestas todas las características nuevas de C++11, pues para eso existe un ISO ;).

Bueno, hasta la próxima, que pienso que sea un artículo sobre el IDE KDevelop, que es el que actualmente utilizo para desarrollar mis aplicaciones (con CMake por debajo).