Novedades de C++17
19/04/2017
Después de tres años de trabajo, C++17 ha sido finalmente estandarizado. Esta nueva versión de C++ incorpora y elimina elementos del lenguaje, con el fin de ponerlo al día y convertirlo en un lenguaje moderno y eficaz. El comité ISO de C++ se ha tomado muy en serio su labor, C++11 supuso este cambio de mentalidad, que se ha mantenido en C++14 y ahora en C++17, la última versión de C++.
Repasemos las noveades que incorpora C++17 respecto a C++14
Ahora podemos incluir una sentencia de inicialización antes de la condición en sentencias if y switch. Esto es particularmente útil si queremos operar con un objeto y desconocemos su validez.
Azúcar sintántico que permite mejorar la legibiliad en ciertas situaciones. Por ejemplo, en el caso de las tuplas, su uso se vuelve trivial.
Esto funciona para multitud de estructuras de datos, como estructuras, arrays, std::array, std::map,...
Ahora es menos necesario que nunca indicar los tipos en ciertas expresiones. Por ejemplo, al crear pares y tuplas:
Esto por supuesto también sirve para estructuras y otras construcciones:
Imagina que quieres hacer una función suma, que admita un número ilimitado de parámetros. En C++17 no se necesita apenas código.
Bastante autoexplicativo
Se usa para suprimir la advertencia del compilador de que no estamos usando una determinada variable.
Permite usar los switch en cascada sin advertencias del compilador.
Ahora es posible definir variables en múltiples sitios con el mismo nombre y que compartan una misma instancia. Es recomendable definirlas en un fichero de cabecera para luego reutilizarlas en ficheros fuente.
Ahora es posible introducir condicionales en tiempo de compilación (similar a las macros #IFDEF pero mejor hecho). Estas expresiones con constexpr, lo que quiere decir que son código C++ que se evalúa en tiempo de compilación, no de ejecución.
Tomado de la programación funcional, se incorpora el tipo optional, que representa un valor que puede existir o no. Este tipo ya existe en Rust bajo el nombre de Option y en Haskell como Maybe.
Descritas como las unions pero bien hechas. Pueden contener variables de los tipos que nosotros indiquemos.
Si con std::variant restringimos los posibles tipos de la variable a los indicados, con std::any admitimos cualquier cosa.
Se añade a la librería estándar este namespace con el tipo path y métodos para iterar y operar con directorios. Dile adiós a las funciones POSIX o Win32 equivalentes.
Muchos de los algoritmos de STL ahora pueden ejecutarse en paralelo bajo demanda. Con std::execution::par indicamos que queremos que el algoritmo se ejecute en paralelo.
Ya hemos visto lo que trae C++17. Ahora veremos que se espera que traiga C++20 en 2020.
Repasemos las noveades que incorpora C++17 respecto a C++14
if-init
Ahora podemos incluir una sentencia de inicialización antes de la condición en sentencias if y switch. Esto es particularmente útil si queremos operar con un objeto y desconocemos su validez.
// ANTES
Device dev = get_device();
if(dev.isOk()){
dev.hacerCosas();
}
// AHORA
if(Device dev = get_device(); dev.isOk()){
dev.hacerCosas();
}
Declaraciones de descomposición
Azúcar sintántico que permite mejorar la legibiliad en ciertas situaciones. Por ejemplo, en el caso de las tuplas, su uso se vuelve trivial.
// FUNCIÓN QUE DEVUELVE TUPLA
std::tuple<int, std::string> funcion();
// C++14
auto tup = funcion();
int i = std::get<0>(tup);
std::string s = std::get<1>(tup);
// C++17
auto [i,s] = funcion();
Esto funciona para multitud de estructuras de datos, como estructuras, arrays, std::array, std::map,...
std::map m = ...;
for(auto && [key, value] : m){
}
Deduction Guides
Ahora es menos necesario que nunca indicar los tipos en ciertas expresiones. Por ejemplo, al crear pares y tuplas:
// ANTES
auto p = std::pair<int,std::string>(42,"Adrianistan");
// AHORA
auto p = std::pair(42,"Adrianistan");
Esto por supuesto también sirve para estructuras y otras construcciones:
template<typename T>
struct Thingy
{
T t;
};
// Observa
Thingy(const char *) -> Thingy<std::string>;
Thingy thing{"A String"}; // thing.t es de tipo std::string
template auto
// ANTES
template <typename T, T v>
struct integral_constant
{
static constexpr T value = v;
};
integral_constant<int, 2048>::value
integral_constant<char, 'a'>::value
// AHORA
template <auto v>
struct integral_constant
{
static constexpr auto value = v;
};
integral_constant<2048>::value
integral_constant<'a'>::value
Fold expressions
Imagina que quieres hacer una función suma, que admita un número ilimitado de parámetros. En C++17 no se necesita apenas código.
template <typename... Args>
auto sum(Args&&... args) {
return (args + ... + 0);
}
Namespaces anidados
Bastante autoexplicativo
// ANTES
namespace A{
namespace B {
bool check();
}
}
// AHORA
namespace A::B {
bool check();
}
Algunos [[atributos]] nuevos
[[maybe_unused]]
Se usa para suprimir la advertencia del compilador de que no estamos usando una determinada variable.
int x = 5;
[[maybe_unused]] bool azar = true;
x = x + 10
[[fallthrough]]
Permite usar los switch en cascada sin advertencias del compilador.
switch (device.status())
{
case sleep:
device.wake();
[[fallthrough]];
case ready:
device.run();
break;
case bad:
handle_error();
break;
}
Variables inline
Ahora es posible definir variables en múltiples sitios con el mismo nombre y que compartan una misma instancia. Es recomendable definirlas en un fichero de cabecera para luego reutilizarlas en ficheros fuente.
// ANTES
// en una cabecera para que la usasen los demás
extern int x;
// solo en un fichero fuente, para inicializarla
int x = 42;
// AHORA
// en la cabecera
inline int x = 42;
if constexpr
Ahora es posible introducir condicionales en tiempo de compilación (similar a las macros #IFDEF pero mejor hecho). Estas expresiones con constexpr, lo que quiere decir que son código C++ que se evalúa en tiempo de compilación, no de ejecución.
template<class T>
void f (T x)
{
if constexpr(std:: is_integral <T>::value) {
implA(x);
}
else if constexpr(std:: floating_point <T>::value) {
implB(x);
}
else
{
implC(x);
}
}
std::optional
Tomado de la programación funcional, se incorpora el tipo optional, que representa un valor que puede existir o no. Este tipo ya existe en Rust bajo el nombre de Option y en Haskell como Maybe.
std::optional opt = f();
if(opt)
g(*opt);
// otra opción de uso si queremos proveer de un reemplazo
std::optional opt = f();
std::cout << opt.value_or(0) << std::endl;
std::variant
Descritas como las unions pero bien hechas. Pueden contener variables de los tipos que nosotros indiquemos.
std::variant<int, double, std::vector> precio; // precio puede ser un int, un double o un std::vector
// comprobar si el valor en un variant es de un determinado tipo
if(std::holds_alternative<double>(precio))
double x = std::get<double>(precio);
std::any
Si con std::variant restringimos los posibles tipos de la variable a los indicados, con std::any admitimos cualquier cosa.
std::any v = ...;
if (v.type() == typeid(int)) {
int i = any_cast<int>(v);
}
std::filesystem
Se añade a la librería estándar este namespace con el tipo path y métodos para iterar y operar con directorios. Dile adiós a las funciones POSIX o Win32 equivalentes.
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
void main(){
fs::path dir = "/";
dir /= "sandbox";
fs::path p = dir / "foobar.txt";
std::cout << p.filename() << "\n";
fs::copy(dir, "/copy", fs::copy_options::recursive);
}
Algoritmos en paralelo
Muchos de los algoritmos de STL ahora pueden ejecutarse en paralelo bajo demanda. Con std::execution::par indicamos que queremos que el algoritmo se ejecute en paralelo.
std::sort(std::execution::par, first, last);
¿Qué novedades se esperan en C++20?
Ya hemos visto lo que trae C++17. Ahora veremos que se espera que traiga C++20 en 2020.
- Módulos. Reemplazar el sistema de includes
- Corrutinas. Mejorar la programación asíncrona
- Contratos. Mejorar la calidad del código
- Conceptos. Mejorar la programación genérica
- Redes. Estandarizar la parte de red en C++ tal y como se ha hecho con std::filesystem
- Rangos. Nuevos contenedores
Referencias:
- https://usingstdcpp.org/using-stdcpp-2016/programa-2016/cpp17-ya-esta-aqui-o-casi/
- https://github.com/tvaneerd/cpp17_in_TTs/blob/master/ALL_IN_ONE.md