Hoja de ruta · en continua actualización
Hoja de ruta de C++ moderno: C++11 → C++23
La mayoría del material para principiantes enseña el C++ de 2003. El código real de 2026 no se parece a eso. Este es el orden en que conviene incorporar las características modernas: cada entrada te muestra la forma antigua, la nueva y por qué importa.
Nota: nuestro editor en el navegador solo cubre el núcleo didáctico (no admite std::string, vector ni características de C++11 o posteriores). Los fragmentos de abajo son para tu compilador de escritorio — consulta cómo compilar C++ (EN).
Etapa 1 — C++11/14: la base (empieza por estas)
Estas no son «avanzadas». Cualquier compilador de la última década las admite y todos los proyectos profesionales las usan. Si un tutorial no las enseña, te está enseñando una pieza de museo.
1. auto — deja que el compilador nombre el tipo
// antiguo
std::vector<std::string>::iterator it = names.begin();
// moderno
auto it = names.begin(); // tipo deducido, sigue siendo tipado estático
Por qué: los tipos se vuelven largos y ruidosos; auto mantiene el tipo correcto incluso cuando cambias el contenedor. Sigue siendo tipado estático — no ocurre nada en tiempo de ejecución.
2. for basado en rangos — itera sin malabares con índices
// antiguo
for (size_t i = 0; i < v.size(); ++i) sum += v[i];
// moderno
for (int x : v) sum += x;
// solo lectura, sin copia — el patrón que verás en todas partes
for (const auto& name : names) cout << name << '\n';
Por qué: sin errores de desfase de uno, sin variable de índice. const auto& debería ser tu opción por defecto: sin copia y sin modificaciones accidentales.
3. Punteros inteligentes — deja de llamar a new/delete a mano
// antiguo — propenso a fugas, inseguro ante excepciones
Widget* w = new Widget();
... // si esto lanza una excepción, w queda sin liberar
delete w;
// moderno — la propiedad es explícita en el tipo
auto w = std::make_unique<Widget>(); // único propietario, se libera automáticamente
auto s = std::make_shared<Widget>(); // propiedad compartida (úsala con moderación)
Por qué: RAII en una línea. unique_ptr debería ser tu opción por defecto para objetos en el heap; shared_ptr, solo cuando la propiedad sea realmente compartida.
4. Lambdas — pasa comportamiento, no solo datos
// ordena con una regla propia, sin escribir una función con nombre
std::sort(people.begin(), people.end(),
[](const Person& a, const Person& b) { return a.age < b.age; });
// captura el estado local por valor ([x]) o por referencia ([&x])
int threshold = 30;
auto over = [threshold](int age) { return age > threshold; };
Por qué: las lambdas convirtieron «pasar una función pequeña» en algo idiomático y abrieron la puerta a los algoritmos modernos. Te las encontrarás en cualquier base de código escrita después de 2011.
5. nullptr, enum class, constexpr
char* p = nullptr; // no es 0 ni NULL — con seguridad de tipos
enum class Color { Red, Green }; // con ámbito: Color::Red, sin int implícito
constexpr int kMax = 100; // se calcula en tiempo de compilación
Etapa 2 — C++17: calidad de vida
6. Structured bindings
std::map<std::string, int> ages;
for (const auto& [name, age] : ages) { // desempaqueta los pares directamente
cout << name << " = " << age << '\n';
}
7. std::optional — «puede que haya un valor» en el tipo
std::optional<int> parse(std::string_view s); // puede fallar
if (auto n = parse(input)) { use(*n); } // sin centinela -1, sin parámetro de salida bool
Por qué: sustituye los valores de retorno mágicos y los parámetros de salida. Ahora el modo de fallo se ve en la firma.
8. std::string_view
void log(std::string_view msg); // sin copia, funciona con literales y cadenas
Etapa 3 — C++20: el plato fuerte (donde lo «moderno» empieza de verdad)
9. Concepts — restricciones que el compilador entiende
template <typename T>
requires std::integral<T>
T twice(T x) { return x * 2; }
// los mensajes de error se vuelven humanos: «T no cumple integral»
// en lugar de páginas de ruido de instanciación de plantillas
Por qué: es la característica estrella de C++20. Convierte los errores de plantilla de algo ilegible en requisitos comprobables.
10. Ranges — pipelines en lugar de cuerpos de bucle
#include <ranges>
auto result = v
| std::views::filter([](int x) { return x % 2 == 0; })
| std::views::transform([](int x) { return x * x; })
| std::views::take(5); // perezoso: nada se ejecuta hasta que se itera
Por qué: se lee como el enunciado del problema. La evaluación perezosa no genera vectores temporales. Es el mayor cambio de estilo desde range-for.
11. Modules — reemplazan el «copia y pega» de #include
// math.cppm
export module math;
export int add(int a, int b) { return a + b; }
// main.cpp
import math; // sin guardas de cabecera, sin reparsear el mundo entero
Por qué: compilaciones más rápidas y fronteras de módulo reales. En 2026, el soporte de las cadenas de herramientas sigue siendo desigual — conócelo, pero todavía no dependas de él en todas partes.
12. Corrutinas, std::format, span, consteval
std::cout << std::format("{} + {} = {}", a, b, a + b); // printf con seguridad de tipos
void process(std::span<int> data); // vista de array, sin degradación a puntero
consteval int square(int x) { return x * x; } // debe ejecutarse en tiempo de compilación
Etapa 4 — C++23 y más allá: lo que está llegando ahora
std::expected<T, E>— manejo de errores sin excepciones ni la ceguera de optional: el tipo de retorno lleva el motivo del fallo.std::print/std::println—formatpor fin se puede usar en una sola línea.std::mdspan— vistas multidimensionales sobre memoria plana (la gente de computación numérica lleva años pidiéndolo).- Deducing
this— parámetros de objeto explícitos, CRTP y mixins más limpios. - Qué seguir: reflection (objetivo C++26), contracts y pattern matching — las tres que cambiarían cómo se lee el código del día a día.
Cómo recorrer esto de verdad
- No lo leas en línea recta. Primero hazte con la Etapa 1 practicando: reescribe un bucle o una ordenación al estilo antiguo que ya hayas escrito.
- Compila con
-std=c++20 -Wall(oc++23). La mitad del «C++ moderno» consiste simplemente en no escribir C++03. - Una característica por problema de práctica. Nuestros 36 problemas están deliberadamente centrados en el núcleo de C++; reescribe uno usando
std::vector+ range-for +autocomo ejercicio. - Lee código real. Elige un proyecto C++ moderno de código abierto y busca con grep
auto&,unique_ptr,std::ranges— fíjate en cómo los usan los proyectos reales.
Relacionado: tipos de datos, vector frente a array (EN), stack frente a heap (EN) y cómo conseguir un compilador de escritorio (EN).