├── Makefile ├── README.md ├── ejemplos ├── c++11 │ ├── Makefile │ ├── decltype.cpp │ ├── lambda.cpp │ ├── thread_local.cpp │ └── udliteral.cpp ├── c++14 │ ├── Makefile │ └── map.cpp └── c++17 │ ├── Makefile │ ├── nodiscard.cpp │ └── optional.cpp ├── presentacion.md └── presentacion.pdf /Makefile: -------------------------------------------------------------------------------- 1 | all: presentacion.md 2 | pandoc -t beamer --slide-level=3 presentacion.md -o presentacion.pdf 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Presentación para una charla en la que se cubren algunos aspectos de los últimos estándares de C++ (11, 14 y 17). 2 | 3 | Contiene algunos ejemplos minimales (algunos demasiado) de uso de distintas características del lenguaje. 4 | -------------------------------------------------------------------------------- /ejemplos/c++11/Makefile: -------------------------------------------------------------------------------- 1 | all: $(patsubst %.cpp, %, $(wildcard *.cpp)) 2 | 3 | %: %.cpp Makefile 4 | g++ $< -o $@ -std=c++11 -pthread 5 | -------------------------------------------------------------------------------- /ejemplos/c++11/decltype.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | int a = 42; 6 | decltype(a) b = a; // int 7 | decltype((a)) c = a; // int& 8 | 9 | c = 43; 10 | 11 | std::cout << a << std::endl; 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ejemplos/c++11/lambda.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | // Las variables globales pueden usarse sin ser capturadas 6 | auto f = [](){ std::cout << "foobar" << std::endl; }; 7 | auto curried_sum = [](int x){ 8 | return [=](int y) { return x+y; }; 9 | }; 10 | 11 | f(); 12 | 13 | auto sum_3 = curried_sum(3); 14 | std::cout << sum_3(4) << std::endl; 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /ejemplos/c++11/thread_local.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | thread_local int tl; 5 | 6 | void do_stuff(int i) 7 | { 8 | tl = i; 9 | 10 | std::cout << tl << std::endl; 11 | } 12 | 13 | int main() 14 | { 15 | int num_threads = 40; 16 | std::thread ts[num_threads]; 17 | 18 | for(int i=0; i 2 | #include 3 | #include 4 | #include 5 | 6 | class Foo { 7 | int bar = 42; 8 | std::string s; 9 | 10 | public: 11 | Foo(std::string s) : s(s) 12 | { 13 | std::cout << s << std::endl; 14 | } 15 | }; 16 | 17 | Foo operator""_foo(const char* literal, size_t l) 18 | { 19 | std::string s; 20 | for(int i=0; i 2 | #include 3 | #include 4 | 5 | auto map = [](auto c, auto f) { 6 | decltype(c) ret; 7 | std::transform(std::begin(c), std::end(c), 8 | std::back_inserter(ret), f); 9 | 10 | return ret; 11 | }; 12 | 13 | int main() 14 | { 15 | std::vector v = {1,2,3,4}; 16 | 17 | auto v2 = map(v, [](int a){ return a*a; }); 18 | 19 | for(auto i : v2) 20 | std::cout << i << std::endl; 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /ejemplos/c++17/Makefile: -------------------------------------------------------------------------------- 1 | all: $(patsubst %.cpp, %, $(wildcard *.cpp)) 2 | 3 | %: %.cpp Makefile 4 | g++ $< -o $@ -std=c++17 -pthread 5 | -------------------------------------------------------------------------------- /ejemplos/c++17/nodiscard.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | void f(int ms) 8 | { 9 | std::cout << "Empieza f" << std::endl; 10 | std::this_thread::sleep_for(std::chrono::milliseconds(ms)); 11 | std::cout << "Termina f" << std::endl; 12 | } 13 | 14 | [[nodiscard]] 15 | auto foo() 16 | { 17 | return std::make_unique(f, 200); 18 | } 19 | 20 | int main() 21 | { 22 | std::unique_ptr f[5]; 23 | for(int i=0; i<5; i++) 24 | { 25 | /* 26 | * La línea comentada y la no comentada resultan en 27 | * ejecuciones muy distintas del programa. 28 | */ 29 | // foo(); 30 | f[i] = foo(); 31 | } 32 | 33 | for(auto& i : f) 34 | i->join(); 35 | 36 | std::cout << "Termina main" << std::endl; 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /ejemplos/c++17/optional.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | auto map_opt = [](auto f, auto o) 5 | { 6 | return o ? std::make_optional(f(o.value())) : std::nullopt; 7 | }; 8 | 9 | auto curried_map_opt = [](auto f){ 10 | return [=](auto o){ 11 | return map_opt(f,o); 12 | }; 13 | }; 14 | 15 | auto flat_map_opt = [](auto f, auto o) 16 | { 17 | return o ? f(o.value()) : std::nullopt; 18 | }; 19 | 20 | auto curried_flat_map_opt = [](auto f){ 21 | return [=](auto o){ 22 | return flat_map_opt(f,o); 23 | }; 24 | }; 25 | 26 | 27 | auto f(int a) 28 | { 29 | return a>=0 ? a-1 : 0; 30 | } 31 | 32 | auto f2(int a) 33 | { 34 | return a>=0 ? std::make_optional(a-1) : std::nullopt; 35 | } 36 | 37 | auto compose_mon2 = [](auto f1, auto f2) 38 | { 39 | return [=](auto a) 40 | { 41 | return flat_map_opt(f1, flat_map_opt(f2, std::make_optional(a))); 42 | }; 43 | }; 44 | 45 | 46 | template 47 | auto compose_mon(F1 f1, F2 f2) 48 | { 49 | return compose_mon2(f1, f2); 50 | } 51 | 52 | template 53 | auto compose_mon(F1 f1, F2 f2, Args... args) 54 | { 55 | return compose_mon(compose_mon2(f1, f2), args...); 56 | } 57 | 58 | int main() 59 | { 60 | std::optional a(38); 61 | 62 | for(int i=0; i<40; i++) 63 | a = flat_map_opt(f2, a); 64 | 65 | auto f3 = compose_mon(f2, f2, f2, f2, [](bool b){ return std::make_optional(42); }); 66 | 67 | std::optional b(42); 68 | b = f3(true); 69 | // Use variadic template to compose 70 | 71 | std::cout << "b: " << b.value() << std::endl; 72 | 73 | if(a) 74 | std::cout << "Valor de a: " << a.value() << std::endl; 75 | else 76 | std::cout << "a no tiene valor" << std::endl; 77 | 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /presentacion.md: -------------------------------------------------------------------------------- 1 | --- 2 | author: Daniel Pozo Escalona 3 | title: C++ moderno 4 | date: 4/11/17 5 | theme: metropolis 6 | 7 | --- 8 | 9 | 10 | # Estándares de C++ 11 | 12 | ### 13 | 14 | C++ está regulado por varios estándares, entre ellos: 15 | 16 | - C++ 03 17 | - C++ 11 18 | - C++ 14 19 | - C++ 17 20 | - C++ 20 (aún no completado) 21 | 22 | ### C++ 03 23 | 24 | Es una revisión al estándar C++ 98, y el que más se enseña en la universidad. Tiene muchas carencias que no lo hacen comparable a otros lenguajes modernos, como una biblioteca estándar pequeña, de modo que [Boost](https://boost.org) y otras se usan como tal. 25 | 26 | ### Siguientes estándares 27 | 28 | Los primeros cambios que modernizan C++ se dan en C++ 11, y cubriremos muchos de ellos. 29 | C++ 14 es una revisión a este estándar. 30 | 31 | C++ 17 es el último estándar ISO aprobado. El próximo será previsiblemente C++ 20. 32 | 33 | # Características añadidas en C++ 11 34 | 35 | ## Ergonomía 36 | 37 | ### Inferencia de tipo 38 | 39 | C++ 11 permite el uso de la palabra clave `auto` 40 | 41 | ```c++ 42 | for(auto i = contenedor_complejo.begin(); 43 | i != contenedor_complejo.end(); i++) 44 | { 45 | // Código superimportante 46 | } 47 | ``` 48 | 49 | Escribir explícitamente el tipo de `i` puede ser difícil y tedioso. 50 | 51 | ### Inferencia de tipo: `decltype` 52 | 53 | EL tipo de una expresión puede ser inferido además en otro contexto, y con resultado potencialmente distinto: al usar `decltype`. 54 | 55 | ```c++ 56 | int a = 42; 57 | decltype(a) b = a; // int 58 | decltype((a)) c = a; // int& 59 | ``` 60 | 61 | ### Comparación: inferencia de tipo en Crystal 62 | 63 | ```ruby 64 | if rand(2) > 0 65 | foo = "hello world" 66 | end 67 | 68 | # foo tiene tipo (String | Nil), 69 | # por lo que esta línea no compila 70 | puts foo.upcase 71 | ``` 72 | 73 | ### `for` basado en rango 74 | 75 | Puede usarse con cualquier objeto que implemente los métodos `begin` y `end` con la semántica usual. 76 | 77 | ```c++ 78 | for(auto i : contenedor) 79 | { 80 | // Código 81 | } 82 | ``` 83 | 84 | ### Soporte de Unicode 85 | 86 | C++ 11 define tres tipos de literales de *string* nuevos: 87 | 88 | ```c++ 89 | u8"Caracteres en UTF-8: \u03BB." 90 | u"Caracteres en UTF-16." 91 | U"Caracteres en UTF-32." 92 | ``` 93 | 94 | Además, cada uno de ellos se puede combinar con el especificador para cadenas *raw*: 95 | 96 | ```c++ 97 | auto s = u8R"(Cadena de caracteres con "comillas")"; 98 | ``` 99 | 100 | ### Literales definidos por el usuario 101 | 102 | Permite definir sufijos que indiquen que ciertos literales se deben construir de una forma especificada por el usuario 103 | 104 | ```c++ 105 | nn::MLP operator""_mlp(const char* literal, size_t l) 106 | { 107 | auto capas = extraer_numeros(literal); 108 | return nn::MLP(capas); 109 | } 110 | 111 | auto p = "0.1,5.7,2"_point; 112 | auto nn = "64, 130, 10"_mlp; 113 | ``` 114 | 115 | ### Ejemplo de uso: [biblioteca de JSON](https://github.com/nlohmann/json) 116 | 117 | El uso de cadenas *raw* y literales definidos por el usuario puede servir para 118 | integrar formatos de texto plano en el lenguaje. 119 | 120 | ```c++ 121 | auto j = R"( 122 | { 123 | "happy": true, 124 | "pi": 3.141 125 | } 126 | )"_json; 127 | ``` 128 | 129 | ## Semántica de movimiento 130 | 131 | ### Referencias a *rvalues* 132 | 133 | En C++ 11 se introducen referencias modificables a *rvalues*, con tipo `T&&`. 134 | Estas referencias se usan para evitar copias profundas de objetos temporales. 135 | 136 | En C++ 03, el siguiente código hace una de las siguientes cosas: 137 | 138 | - Llama al constructor de copia del tipo de `v` con el valor de retorno de la función como argumento. 139 | - Aplica la *optimización de valor de retorno*, que consiste en cambiar el código para que la función tome una referencia a `v` y lo modifique directamente, pudiendo ignorar efectos colaterales del constructor de copia. 140 | 141 | ```c++ 142 | v = devuelve_vector_gigante(); 143 | ``` 144 | 145 | ### Referencias a *rvalues* 146 | 147 | En C++ 11, el tipo de `v` puede definir un constructor que tome una referencia a un objeto temporal, y apropiarse de su estado, normalmente copiando punteros en lugar de vectores completos. 148 | 149 | El tipo `std::vector` y otros muchos de la biblioteca estándar implementan un constructor de este tipo. 150 | 151 | ## Programación orientada a objetos 152 | 153 | ### Inicialización de datos miembros no estáticos 154 | 155 | Hasta ahora, había que inicializar todos los datos miembro de una clase explícitamente en el constructor. 156 | 157 | ```c++ 158 | class Foo { 159 | int bar = 42; 160 | int foobar; 161 | 162 | public: 163 | // bar vale 42 164 | Foo(int foobar) : foobar(foobar) {} 165 | }; 166 | ``` 167 | 168 | ### `default` y `delete` 169 | 170 | Se añaden palabras clave para indicar explícitamente que una clase va a usar una de las funciones especiales que el compilador provee por defecto (constructor, destructor, constructor de copia, ...) o que no permite llamarlos. 171 | 172 | ```c++ 173 | class Foo { 174 | public: 175 | Foo() = default; 176 | 177 | Foo(Foo&) = delete; 178 | Foo& operator=(Foo&) = delete; 179 | 180 | Foo(int a); 181 | }; 182 | ``` 183 | 184 | ### `override` y `final` 185 | 186 | También se puede indicar explícitamente que se está redefiniendo un método de una clase base, o que este no se puede redefinir, para que el compilador lo fuerce. 187 | 188 | ```c++ 189 | class Foo { 190 | public: 191 | void f() final; 192 | void f2(std::vector); 193 | }; 194 | 195 | class Bar : public Foo { 196 | public: 197 | void f(); // Error 198 | void f2(std::vector) override; // Error 199 | }; 200 | ``` 201 | 202 | ## Programación funcional 203 | 204 | ### Funciones anónimas 205 | 206 | También conocidas como funciones *lambda*. 207 | 208 | ```c++ 209 | auto id = [](int x) { return x; }; 210 | auto sum = [](int x, int y){ return x+y; }; 211 | auto curried_sum = [](int x){ 212 | return [=](int y) { return x+y; }; 213 | }; 214 | ``` 215 | 216 | ### Clausuras 217 | 218 | Permiten que una función anónima use variables definidas en su entorno, por valor o por referencia: 219 | 220 | ```c++ 221 | int a=0, b=1; 222 | 223 | // Toma a por valor y b por referencia 224 | auto f = [a,&b]() { b = 2; }; 225 | 226 | // Toma todo el entorno por referencia 227 | auto g = [&](){ b = 3; }; 228 | 229 | // Toma todo el entorno por valor 230 | auto h = [=]() { std::cout << a << std::endl; }; 231 | ``` 232 | ### 233 | 234 | \begin{alertblock}{Las \textit{lambdas} no son puras} 235 | Aunque no se especifique ninguna clausura, una \textit{lambda} puede usar variables globales. Por tanto, no verifican la propiedad de transparencia referencial. 236 | \end{alertblock} 237 | 238 | ## Seguridad 239 | 240 | ### Punteros 241 | 242 | #### Constante `nullptr` 243 | 244 | Es de tipo `nullptr_t`, que se puede convertir a cualquier tipo de puntero y a `bool`, y a ningún otro tipo integral. 245 | 246 | ```c++ 247 | void foo(char*); 248 | void foo(int); 249 | 250 | // Llama a foo(int) 251 | foo(NULL); 252 | // Llama a foo(char*) 253 | foo(nullptr); 254 | ``` 255 | 256 | ### Punteros automáticos 257 | 258 | Sirven para expresar semántica de pertenencia de un objeto a una o varias referencias, de forma que siempre se determine en qué momento se destruye el objeto y se liberan los recursos asociados. 259 | 260 | Esto soluciona el problema de que en C++ los objetos dinámicos no se destruyen al terminar el ámbito en el que fueron creados, lo cual hacía inútil la semántica RAII en estos casos. 261 | 262 | ### Punteros automáticos 263 | 264 | #### `unique_ptr` 265 | 266 | Sirve para expresar la pertenencia de un objeto a una única referencia. 267 | 268 | ```c++ 269 | std::unique_ptr p(new Foo); 270 | // No compila: semántica de 271 | // pertenencia en tiempo de compilación 272 | std::unique_ptr q = p; 273 | ``` 274 | 275 | El destructor de `unique_ptr` destruye el objeto, es decir, implementa la semántica RAII. 276 | 277 | ```c++ 278 | { 279 | std::unique_ptr p(new Foo); 280 | } // Foo es destruido 281 | ``` 282 | 283 | ### Punteros automáticos 284 | 285 | #### `shared_ptr` 286 | 287 | Sirve para expresar la pertenencia de un objeto a varias referencias. Es un puntero con conteo de referencias, de forma que el puntero que, al ser destruido, ponga la cuenta a cero, es el responsable de destruir el objeto. 288 | 289 | ### Punteros automáticos 290 | 291 | ```c++ 292 | { 293 | // Cuenta a uno 294 | auto p1 = std::make_shared(new Foo(43)); 295 | 296 | { 297 | // Cuenta a dos 298 | auto p2(p1); 299 | } // Cuenta a uno 300 | 301 | } // Cuenta a cero: destruye Foo 302 | ``` 303 | 304 | ### Punteros automáticos 305 | 306 | #### `weak_ptr` 307 | 308 | Es una referencia "observadora" que depende de un `shared_ptr`. No afecta al conteo de referencias del `shared_ptr` asociado. Puede observar el estado del objeto (si ha sido destruido) y crear nuevas referencias compartidas a él. 309 | 310 | ### Comparación: semántica de pertenencia en Rust 311 | 312 | En Rust, para un objeto: 313 | 314 | - Siempre hay una variable que lo posee, y es única. 315 | - Cuando la variable sale de ámbito, el objeto se destruye. 316 | 317 | Además: 318 | 319 | - Las siguientes posibilidades son exclusivas: 320 | - Existe una referencia que permite modificar del objeto. 321 | - Existen varias referencias que no permiten modificar el objeto. 322 | - Cualquier referencia siempre es válida. 323 | 324 | ## Concurrencia y paralelismo 325 | 326 | ### Concurrencia y paralelismo 327 | 328 | En C++ 11 se introducen primitivas de concurrencia y sincronización en la biblioteca estándar. 329 | 330 | ### `thread_local` y `std::thread` 331 | 332 | `thread_local` es un nuevo especificador de almacenamiento, que indica que una variable tiene una copia por cada hilo de ejecución del programa. Sin embargo, *no* es una variable local, es global a cada hilo. 333 | 334 | `std::thread`: un objeto de este tipo representa un hilo de ejecución. 335 | 336 | \begin{block}{Ejemplo} 337 | \texttt{thread\_local.cpp} 338 | \end{block} 339 | 340 | ### `future` 341 | 342 | Un *futuro* representa un valor posiblemente indeterminado, normalmente porque no ha sido computado, pero que será determinado en algún momento. 343 | 344 | La función `std::async` nos permite crear un futuro a partir de un objeto con operador de llamada a función, llamándolo de forma concurrente o diferida. 345 | 346 | ### `future` 347 | 348 | ```c++ 349 | for(auto& f : fut) 350 | { 351 | f = std::async(std::launch::async, generar_solucion, 352 | aleatorio()); 353 | } 354 | 355 | optima = std::accumulate(fut.begin(), fut.end(), def, 356 | [](sol a, std::future& b){ 357 | auto v_b = b.get(); 358 | return v_heuristico(a) > v_heuristico(v_b) 359 | ? a : v_b;}); 360 | ``` 361 | 362 | ## Otro 363 | 364 | ### Sintaxis estándar para atributos 365 | 366 | ```c++ 367 | #pragma once // Directiva 368 | // Sintaxis específica de Microsoft 369 | __declspec(dllimport) 370 | // Sintaxis específica de GNU 371 | __attribute__((constructor)) 372 | 373 | [[attr_name]] // Sintaxis estandarizada 374 | ``` 375 | 376 | En C++ 14 y 17 se introducen algunos atributos útiles. 377 | 378 | ## Metaprogramación 379 | 380 | ### Plantillas con número variable de argumentos 381 | 382 | ```c++ 383 | template 384 | auto compose_mon(F1 f1, F2 f2) 385 | { 386 | return compose_mon2(f1, f2); 387 | } 388 | 389 | template 390 | auto compose_mon(F1 f1, F2 f2, Args... args) 391 | { 392 | return compose_mon(compose_mon2(f1, f2), args...); 393 | } 394 | ``` 395 | 396 | ### Aserciones estáticas 397 | 398 | Son aserciones que se comprueban en tiempo de compilación, después de 399 | la etapa de preprocesamiento. 400 | 401 | ```c++ 402 | template class MiClasse { 403 | static_assert(std::is_enum::value, 404 | "T debe ser de al menos 64 bits"); 405 | }; 406 | ``` 407 | 408 | 409 | # Características añadidas en C++ 14 410 | 411 | ### `auto` en parámetros de *lambdas* 412 | 413 | Permite crear *lambdas* más genéricas 414 | 415 | ```c++ 416 | auto id = [](auto x){ return x }; 417 | auto map = [](auto c, auto f) { 418 | decltype(c) ret; 419 | std::transform(std::begin(c), std::end(c), 420 | std::back_inserter(ret), f); 421 | 422 | return ret; 423 | }; 424 | ``` 425 | 426 | ### Semántica de movimiento a *lambdas* 427 | 428 | Una *lambda* podía tomar variables de su entorno por valor o por referencia, pero no podía apropiarse de ellas. Se introduce sintaxis para ello: 429 | 430 | ```c++ 431 | auto unwrap_and_destroy = [p = std::move(ptr)](){ 432 | return *p; }; 433 | ``` 434 | 435 | ### Atributo `deprecated` 436 | 437 | Sirve para que el compilador advierta al usuario de que está usando una entidad que va a ser eliminada en versiones futuras de una biblioteca 438 | 439 | ```c++ 440 | [[deprecated("g deprecated")]] 441 | int g() 442 | { 443 | return 4; 444 | } 445 | 446 | struct [[deprecated("s deprecated")]] s { 447 | int a; 448 | }; 449 | ``` 450 | 451 | ### `std::make_unique` 452 | 453 | En C++ 11 existía `std::make_shared` para crear un objeto de tipo `std::shared_ptr`, sin embargo, había que invocar directamente el constructor de `std::unique_ptr`. 454 | 455 | ```c++ 456 | auto p = std::make_unique(42); 457 | ``` 458 | 459 | # Características añadidas en C++ 17 460 | 461 | ### Asignaciones estructuradas 462 | 463 | Funciona con `std::tuple`, `std::pair`, `std::array` y algunas estructuras. 464 | 465 | ```c++ 466 | using point3d = std::tuple; 467 | 468 | point3d f(); 469 | 470 | auto [x, y, z] = f(); 471 | ``` 472 | 473 | ### El atributo `nodiscard` 474 | 475 | Al principio... 476 | 477 | ```c 478 | (void)printf("Código que has podido ver en la ETSIIT\n"); 479 | ``` 480 | 481 | ### El atributo `nodiscard` 482 | 483 | Muchos códigos de error pueden ser ignorados sin problema, y el compilador no suele advertir de ello. 484 | Otros no: 485 | 486 | ```c++ 487 | auto foo() 488 | { 489 | return std::make_unique(f, 200); 490 | } 491 | ``` 492 | 493 | \begin{block}{Ejemplo} 494 | \texttt{c++14/nodiscard.cpp} 495 | \end{block} 496 | 497 | ### El atributo `nodiscard` 498 | 499 | En este caso, podemos forzar una advertencia del compilador marcando `foo` con el atributo `nodiscard`. 500 | 501 | ```c++ 502 | [[nodiscard]] 503 | auto foo() 504 | { 505 | return std::make_unique(f, 200); 506 | } 507 | ``` 508 | 509 | ### `std::optional` 510 | 511 | Es un tipo que almacena un valor opcional de otro tipo, sin reserva de memoria dinámica. 512 | 513 | ```c++ 514 | auto map_opt = [](auto f, auto o) 515 | { 516 | return o ? std::make_optional(f(o.value())) 517 | : std::nullopt; 518 | }; 519 | 520 | auto flat_map_opt = [](auto f, auto o) 521 | { 522 | return o ? f(o.value()) : std::nullopt; 523 | }; 524 | ``` 525 | 526 | ### `std::variant` 527 | 528 | Funciona como una unión, pero permite comprobar el tipo que almacena en un momento dado. 529 | 530 | ```c++ 531 | std::variant v(true); 532 | 533 | if(std::holds_alternative(v)) 534 | // No se ejecuta 535 | ``` 536 | 537 | ### Comparación: tipos de datos algebraicos 538 | 539 | ```haskell 540 | data Exp = Var Int | 541 | Sum Exp Exp | 542 | Product Exp Exp 543 | ``` 544 | 545 | Cualquier lenguaje que posea tipos de datos algebraicos tiene mucha más capacidad expresiva 546 | a este respecto. 547 | 548 | ### Versiones paralelas de algoritmos de la biblioteca estándar 549 | 550 | Los algoritmos definidos en la cabecera `` ganan un parámetro de plantilla, 551 | que indica si pueden ser paralelizados por la implementación. 552 | 553 | ```c++ 554 | auto sum = std::reduce(std::execution_policy::par, 555 | v.begin(), v.end(), 0); 556 | ``` 557 | 558 | # Bastantes cosas más 559 | 560 | ### 561 | 562 | - [C++11 en Wikipedia](https://en.wikipedia.org/wiki/C%252B%252B11) 563 | - [C++14 en Wikipedia](https://en.wikipedia.org/wiki/C%252B%252B14) 564 | - [C++17 en Wikipedia](https://en.wikipedia.org/wiki/C%252B%252B17) 565 | - [Awesome Modern C++](https://github.com/rigtorp/awesome-modern-cpp) 566 | 567 | # Fin 568 | -------------------------------------------------------------------------------- /presentacion.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danipozo/charla-cpp-moderno/a22765a44bae4829d17f4788eaa382f5fe66b8f7/presentacion.pdf --------------------------------------------------------------------------------