Meta Title (59 characters)
Modern C++ Tutorial: C++11 to C++23 Features Guide
Meta Description (158 characters)
Learn Modern C++ from C++11 to C++23 with auto, nullptr, constexpr, lambda, optional, variant, ranges, concepts, filesystem, and examples.
Search Keywords
Modern C++, C++11 Tutorial, C++14 Features, C++17 Tutorial, C++20 Features, C++23 Overview, auto Keyword, nullptr, constexpr, Lambda Expressions, Structured Bindings, std::optional, std::variant, std::filesystem, Concepts, Ranges, C++ Programming
Module 27: Modern C++ (C++11 – C++23)
Introduction
Modern C++ refers to the evolution of the C++ language beginning with C++11. Each new standard has introduced features that make C++ safer, faster, more expressive, and easier to write.
Before C++11, many tasks required verbose code. Modern C++ simplifies common programming patterns while improving performance through features like move semantics, smart pointers, lambdas, and compile-time programming.
This module provides an overview of the most important features introduced from C++11 to C++23.
Learning Objectives
After completing this module, you will understand:
- Evolution of Modern C++
- C++11 features
- C++14 improvements
- C++17 additions
- C++20 innovations
- C++23 overview
autonullptrconstexpr- Lambda expressions
- Structured bindings
std::optionalstd::variant- Filesystem library
- Concepts
- Ranges
Evolution of Modern C++
| Standard | Release Year | Major Highlights |
|---|---|---|
| C++11 | 2011 | auto, nullptr, lambda, move semantics |
| C++14 | 2014 | Generic lambdas, constexpr improvements |
| C++17 | 2017 | Structured bindings, optional, variant, filesystem |
| C++20 | 2020 | Concepts, ranges, modules, coroutines |
| C++23 | 2023 | Library improvements, expected, print, mdspan |
Why Modern C++?
Older C++ code was often verbose.
Example (Before C++11)
1std::vector<int>::iterator it = numbers.begin();
Modern C++
1auto it = numbers.begin();
Cleaner and easier to read.
C++11 Features
C++11 introduced the biggest update in C++ history.
Major features:
- auto
- nullptr
- Lambda expressions
- Move semantics
- Smart pointers
- Range-based for loop
- constexpr
- Uniform initialization
auto Keyword
auto allows the compiler to automatically determine the variable's type.
Syntax
1auto variable = value;
Example
1#include <iostream> 2#include <vector> 3 4int main() 5{ 6 auto age = 25; 7 auto pi = 3.14159; 8 auto name = std::string("Tech3Space"); 9 10 std::cout << age << std::endl; 11 std::cout << pi << std::endl; 12 std::cout << name << std::endl; 13}
Output
125 23.14159 3Tech3Space
Range-Based For Loop
1#include <iostream> 2#include <vector> 3 4int main() 5{ 6 std::vector<int> numbers = {10,20,30,40}; 7 8 for(auto value : numbers) 9 { 10 std::cout << value << " "; 11 } 12}
Output
110 20 30 40
nullptr
Before C++11:
1int* ptr = NULL;
Modern C++
1int* ptr = nullptr;
Example
1#include <iostream> 2 3int main() 4{ 5 int* ptr = nullptr; 6 7 if(ptr == nullptr) 8 { 9 std::cout << "Pointer is null"; 10 } 11}
Output
1Pointer is null
constexpr
constexpr allows values and functions to be evaluated at compile time.
Example
1#include <iostream> 2 3constexpr int square(int x) 4{ 5 return x * x; 6} 7 8int main() 9{ 10 constexpr int value = square(8); 11 12 std::cout << value; 13}
Output
164
Lambda Expressions
Lambda expressions are anonymous functions.
Syntax
1[capture](parameters) 2{ 3 // body 4};
Example
1#include <iostream> 2 3int main() 4{ 5 auto add = [](int a, int b) 6 { 7 return a + b; 8 }; 9 10 std::cout << add(10,20); 11}
Output
130
Lambda with Capture
1#include <iostream> 2 3int main() 4{ 5 int number = 50; 6 7 auto show = [number]() 8 { 9 std::cout << number; 10 }; 11 12 show(); 13}
Output
150
Smart Pointers (C++11)
1#include <iostream> 2#include <memory> 3 4int main() 5{ 6 auto ptr = std::make_unique<int>(100); 7 8 std::cout << *ptr; 9}
Output
1100
Move Semantics (C++11)
1#include <iostream> 2#include <string> 3#include <utility> 4 5int main() 6{ 7 std::string a = "Modern C++"; 8 9 std::string b = std::move(a); 10 11 std::cout << b; 12}
Output
1Modern C++
C++14 Features
Major additions:
- Generic lambdas
- Improved constexpr
- Binary literals
- Variable templates
Generic Lambda
1#include <iostream> 2 3int main() 4{ 5 auto multiply = [](auto a, auto b) 6 { 7 return a * b; 8 }; 9 10 std::cout << multiply(5,6) << std::endl; 11 std::cout << multiply(2.5,4.0); 12}
Output
130 210
Binary Literals
1#include <iostream> 2 3int main() 4{ 5 int value = 0b1010; 6 7 std::cout << value; 8}
Output
110
C++17 Features
Major additions
- Structured bindings
- Optional
- Variant
- Filesystem
- if constexpr
- Fold expressions
Structured Bindings
1#include <iostream> 2#include <tuple> 3 4int main() 5{ 6 std::tuple<int,std::string> student = {101,"Ankit"}; 7 8 auto [id,name] = student; 9 10 std::cout << id << std::endl; 11 std::cout << name; 12}
Output
1101 2Ankit
std::optional
Represents a value that may or may not exist.
1#include <iostream> 2#include <optional> 3 4std::optional<int> divide(int a,int b) 5{ 6 if(b==0) 7 return std::nullopt; 8 9 return a/b; 10} 11 12int main() 13{ 14 auto result = divide(20,5); 15 16 if(result) 17 std::cout<<*result; 18}
Output
14
std::variant
Stores one of several possible types.
1#include <iostream> 2#include <variant> 3 4int main() 5{ 6 std::variant<int,std::string> value; 7 8 value = 100; 9 std::cout << std::get<int>(value) << std::endl; 10 11 value = "Tech3Space"; 12 std::cout << std::get<std::string>(value); 13}
Output
1100 2Tech3Space
std::filesystem
Allows file and directory manipulation.
1#include <filesystem> 2#include <iostream> 3 4namespace fs = std::filesystem; 5 6int main() 7{ 8 fs::path folder = "."; 9 10 std::cout << fs::exists(folder); 11}
Output
11
C++20 Features
Major additions
- Concepts
- Ranges
- Coroutines
- Modules
- Calendar Library
Concepts
Concepts define compile-time constraints on template parameters.
1#include <concepts> 2#include <iostream> 3 4template<typename T> 5requires std::integral<T> 6T add(T a,T b) 7{ 8 return a+b; 9} 10 11int main() 12{ 13 std::cout << add(5,10); 14}
Output
115
Passing a non-integral type (such as double) will produce a compile-time error.
Ranges
Ranges simplify working with containers.
1#include <iostream> 2#include <ranges> 3#include <vector> 4 5int main() 6{ 7 std::vector<int> numbers={1,2,3,4,5}; 8 9 for(int value : numbers | std::views::filter([](int x) 10 { 11 return x%2==0; 12 })) 13 { 14 std::cout<<value<<" "; 15 } 16}
Output
12 4
C++23 Overview
C++23 focuses on improving the standard library and developer productivity.
Major additions include:
std::expectedstd::printstd::mdspan- Improved ranges
- Better formatting library
- More constexpr support
std::expected (C++23)
std::expected provides a cleaner alternative to returning error codes.
1#include <expected> 2#include <iostream> 3#include <string> 4 5std::expected<int,std::string> divide(int a,int b) 6{ 7 if(b==0) 8 return std::unexpected("Division by zero"); 9 10 return a/b; 11} 12 13int main() 14{ 15 auto result = divide(20,4); 16 17 if(result) 18 std::cout<<result.value(); 19 else 20 std::cout<<result.error(); 21}
Output
15
Feature Comparison
| Feature | C++11 | C++14 | C++17 | C++20 | C++23 |
|---|---|---|---|---|---|
| auto | ✅ | ✅ | ✅ | ✅ | ✅ |
| nullptr | ✅ | ✅ | ✅ | ✅ | ✅ |
| constexpr | ✅ | Improved | Improved | Improved | Improved |
| Lambda | ✅ | Generic | Improved | Improved | Improved |
| Structured Bindings | ❌ | ❌ | ✅ | ✅ | ✅ |
| optional | ❌ | ❌ | ✅ | ✅ | ✅ |
| variant | ❌ | ❌ | ✅ | ✅ | ✅ |
| filesystem | ❌ | ❌ | ✅ | ✅ | ✅ |
| Concepts | ❌ | ❌ | ❌ | ✅ | ✅ |
| Ranges | ❌ | ❌ | ❌ | ✅ | Improved |
Real-World Example
Imagine building a modern banking system.
- auto reduces repetitive type declarations.
- nullptr prevents null pointer ambiguity.
- constexpr performs calculations during compilation.
- Lambdas simplify sorting and callbacks.
- optional represents missing account information.
- variant stores different transaction types.
- filesystem manages reports and documents.
- concepts ensure templates accept only valid types.
- ranges process collections with clean, expressive code.
Best Practices
✅ Prefer auto when the type is obvious.
✅ Use nullptr instead of NULL.
✅ Use constexpr for compile-time constants.
✅ Prefer lambda expressions for short functions.
✅ Use std::optional instead of sentinel values.
✅ Use std::variant instead of unions or complex inheritance when a value can have one of several types.
✅ Use std::filesystem for file operations instead of platform-specific APIs.
✅ Use concepts to write safer templates.
✅ Use ranges to write cleaner container algorithms.
Common Mistakes
Overusing auto
Less readable
1auto x = calculateSomethingComplex();
Prefer explicit types when they improve readability.
Using NULL
Wrong
1int* ptr = NULL;
Correct
1int* ptr = nullptr;
Ignoring optional
Wrong
1int result = divide(a,b);
Better
1std::optional<int> result = divide(a,b);
Interview Questions
1. What is Modern C++?
Modern C++ refers to language standards from C++11 onwards, introducing safer, more expressive, and higher-performance features.
2. What is the purpose of auto?
It lets the compiler deduce the variable type automatically.
3. Why is nullptr better than NULL?
nullptr has its own type (std::nullptr_t) and avoids ambiguity in overloaded functions.
4. What is a lambda expression?
An anonymous function object that can capture variables from its surrounding scope.
5. What is constexpr?
A keyword that enables values or functions to be evaluated at compile time when possible.
6. What is std::optional?
A wrapper that represents either a valid value or no value.
7. What is std::variant?
A type-safe union capable of holding one value from a predefined set of types.
8. What are concepts?
Compile-time constraints that specify which types are valid for templates.
9. What are ranges?
A modern library that provides expressive ways to filter, transform, and iterate over collections.
10. Which C++ standard introduced structured bindings?
C++17.
Module Summary
In this module, you learned:
- The evolution of Modern C++ from C++11 to C++23
- Important features introduced in each standard
- How to use
auto,nullptr,constexpr, and lambda expressions - Working with
std::optional,std::variant, andstd::filesystem - Writing safer templates using concepts
- Processing collections using ranges
- Best practices for writing clean, modern, efficient, and maintainable C++ code
You now have a strong foundation in Modern C++ and are prepared to use the language features introduced over the last decade to build high-performance, production-quality applications.