C++ has evolved significantly over the years with the introduction of new features and enhancements in the standards C++11, C++14, C++17, and C++20. These features aim to improve productivity, performance, and expressiveness while maintaining backward compatibility with existing codebases.
The auto
keyword allows the compiler to deduce the type of a variable from its initializer, reducing verbosity and enhancing code readability.
auto x = 10; // x is deduced to be of type int
auto y = 3.14; // y is deduced to be of type double
The range-based for loop simplifies iteration over elements in a container, providing a cleaner syntax compared to traditional loops.
std::vector vec = {1, 2, 3, 4, 5};
for (auto& elem : vec) {
std::cout << elem << " ";
}
// Output: 1 2 3 4 5
Lambda expressions allow inline definition of anonymous functions, improving code modularity and readability.
auto sum = [](int a, int b) { return a + b; };
std::cout << sum(5, 3); // Output: 8
Move semantics enable efficient transfer of resources (e.g., memory ownership) from one object to another, reducing unnecessary copying and improving performance.
std::vector source = {1, 2, 3};
std::vector destination = std::move(source);
C++14, released in 2014, builds upon the foundation laid by C++11, introducing additional features and improvements. Some notable features include:
Variable templates allow the definition of parameterized variables, similar to function templates.
template
constexpr T pi = T(3.1415926535897932385);
double circumference(double r) {
return 2 * pi * r;
}
C++14 extends lambda expressions to support generic parameters, enabling more flexible and reusable code.
auto add = [](auto a, auto b) { return a + b; };
std::cout << add(3, 4) << std::endl; // Output: 7
std::cout << add(3.5, 4.5) << std::endl; // Output: 8
C++14 introduces binary literals and digit separators for improved readability of numeric constants.
int binary = 0b101010; // Binary literal
int million = 1'000'000; // Digit separator for readability
C++17, released in 2017, continues the evolution of the language with new features and enhancements. Some significant features include:
Structured bindings allow unpacking of tuples and other structured types into individual variables.
std::pair point = {10, 20};
auto [x, y] = point;
std::cout << "x: " << x << ", y: " << y << std::endl;
C++17 introduces the inline
specifier for variables, allowing their definition in header files without violating the one-definition rule.
inline int value = 42; // Defined in header file
C++17 includes a standard filesystem library (`std::filesystem`) for file and directory manipulation, providing a modern and portable interface for working with the filesystem.
#include
namespace fs = std::filesystem;
int main() {
fs::path path = "/path/to/directory";
for (const auto& entry : fs::directory_iterator(path)) {
std::cout << entry.path() << std::endl;
}
return 0;
}
C++20, released in 2020, brings further enhancements to the language, standard library, and compiler support. Some notable features include:
Concepts allow template parameters to be constrained by specifying requirements on their types, enabling clearer error messages and improved compile-time checking.
template
concept Integral = std::is_integral_v;
template
void print(T value) {
std::cout << value << std::endl;
}
C++20 introduces ranges, which provide a more expressive and composable way to work with sequences of elements.
#include
#include
#include
int main() {
std::vector numbers = {1, 2, 3, 4, 5};
auto even_numbers = numbers | std::views::filter([](int n) { return n % 2 == 0; });
for (int n : even_numbers) {
std::cout << n << " ";
}
return 0;
}
Coroutines allow functions to be suspended and resumed, enabling asynchronous programming with more readable and maintainable code.
#include
#include
struct MyCoroutine {
struct promise_type {
int current_value;
auto get_return_object() {
return MyCoroutine{std::coroutine_handle::from_promise(*this)};
}
auto initial_suspend() { return std::suspend_never{}; }
auto final_suspend() noexcept { return std::suspend_never{}; }
void unhandled_exception() {}
void return_void() {}
auto yield_value(int value) {
current_value = value;
return std::suspend_always{};
}
};
std::coroutine_handle coroutine;
MyCoroutine(std::coroutine_handle h) : coroutine(h) {}
~MyCoroutine() { coroutine.destroy(); }
bool next() {
coroutine.resume();
return !coroutine.done();
}
int value() const { return coroutine.promise().current_value; }
};
MyCoroutine generate() {
co_yield 1;
co_yield 2;
co_yield 3;
}
int main() {
MyCoroutine generator = generate();
while (generator.next()) {
std::cout << generator.value() << std::endl;
}
return 0;
}
// output //
1
2
3
MyCoroutine
struct is defined to represent a coroutine. It contains:promise_type
struct: This struct defines the promise type associated with the coroutine. It contains the necessary functions required for coroutine operations, such as get_return_object
, initial_suspend
, final_suspend
, unhandled_exception
, and return_void
. Additionally, it defines the yield_value
function, which suspends the coroutine and returns a value.coroutine
member of type std::coroutine_handle<promise_type>
: This member holds the handle to the coroutine.generate
):generate
function returns a MyCoroutine
object.generate
function, the co_yield
keyword is used to yield values (in this case, integers 1, 2, and 3) from the coroutine.main
function, a MyCoroutine
object named generator
is created by calling the generate
function.while
loop is used to iterate over the coroutine. Inside the loop:next
function of the generator
object is called, which resumes the coroutine execution until it’s done.value
function is called to retrieve the current value yielded by the coroutine, which is then printed to the console.The evolution of C++ from C++11 to C++20 has introduced numerous features and improvements that enhance the expressiveness, performance, and safety of the language. By understanding and leveraging these features, developers can write more efficient, maintainable, and robust C++ code.In this chapter, we've explored the key features introduced in each C++ standard update, from C++11 to C++20, with examples to illustrate their usage. By staying informed about the latest developments in the C++ language and standard library, developers can continue to push the boundaries of what's possible and write code that meets the demands of modern software development. Happy coding !❤️