Claude
Skills
Sign in
Back

cpp-modern-features

Included with Lifetime
$97 forever

Use when modern C++ features from C++11/14/17/20 including auto, lambdas, range-based loops, structured bindings, and concepts.

General

What this skill does


# Modern C++ Features

Modern C++ (C++11 and beyond) introduced significant improvements that make
C++ more expressive, safer, and easier to use. This skill covers essential
modern features including type inference, lambda expressions, range-based
loops, smart initialization, and the latest C++20 additions.

## Auto Type Inference

The `auto` keyword enables automatic type deduction, reducing verbosity while
maintaining type safety.

```cpp
#include <iostream>
#include <vector>
#include <map>
#include <string>

void auto_examples() {
    // Simple type inference
    auto x = 42;              // int
    auto pi = 3.14159;        // double
    auto name = "Alice";      // const char*
    auto message = std::string("Hello");  // std::string

    // Iterator simplification
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    // Before C++11
    for (std::vector<int>::iterator it = numbers.begin();
         it != numbers.end(); ++it) {
        std::cout << *it << " ";
    }

    // With auto
    for (auto it = numbers.begin(); it != numbers.end(); ++it) {
        std::cout << *it << " ";
    }

    // Complex types
    std::map<std::string, std::vector<int>> data;
    auto it = data.find("key");  // Much cleaner than full type

    // Return type deduction (C++14)
    auto multiply = [](int a, int b) { return a * b; };

    // Structured bindings (C++17)
    std::map<std::string, int> scores = {{"Alice", 95}, {"Bob", 87}};
    for (const auto& [name, score] : scores) {
        std::cout << name << ": " << score << "\n";
    }
}
```

## Lambda Expressions

Lambdas provide inline anonymous functions, essential for modern C++
algorithms and callbacks.

```cpp
#include <algorithm>
#include <vector>
#include <functional>
#include <iostream>

void lambda_examples() {
    std::vector<int> numbers = {5, 2, 8, 1, 9, 3};

    // Basic lambda
    auto print = [](int n) { std::cout << n << " "; };
    std::for_each(numbers.begin(), numbers.end(), print);

    // Lambda with capture
    int threshold = 5;
    auto above_threshold = [threshold](int n) { return n > threshold; };

    // Capture by value [=]
    auto sum_above = [=]() {
        int sum = 0;
        for (int n : numbers) {
            if (n > threshold) sum += n;
        }
        return sum;
    };

    // Capture by reference [&]
    int count = 0;
    auto count_above = [&count, threshold](int n) {
        if (n > threshold) count++;
    };
    std::for_each(numbers.begin(), numbers.end(), count_above);

    // Generic lambda (C++14)
    auto generic_print = [](const auto& item) {
        std::cout << item << " ";
    };

    // Lambda as comparator
    std::sort(numbers.begin(), numbers.end(),
              [](int a, int b) { return a > b; });  // Descending

    // Mutable lambda
    auto counter = [count = 0]() mutable {
        return ++count;
    };

    std::cout << counter() << "\n";  // 1
    std::cout << counter() << "\n";  // 2
}

// Returning lambdas
std::function<int(int)> make_multiplier(int factor) {
    return [factor](int n) { return n * factor; };
}
```

## Range-Based For Loops

Range-based for loops provide clean, safe iteration over containers and
ranges.

```cpp
#include <vector>
#include <map>
#include <string>
#include <iostream>

void range_based_loops() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    // Basic iteration
    for (int n : numbers) {
        std::cout << n << " ";
    }

    // By reference (for modification)
    for (int& n : numbers) {
        n *= 2;
    }

    // By const reference (efficient for large objects)
    std::vector<std::string> names = {"Alice", "Bob", "Charlie"};
    for (const auto& name : names) {
        std::cout << name << "\n";
    }

    // With structured bindings (C++17)
    std::map<std::string, int> ages = {
        {"Alice", 30},
        {"Bob", 25},
        {"Charlie", 35}
    };

    for (const auto& [name, age] : ages) {
        std::cout << name << " is " << age << " years old\n";
    }

    // Initializer in for loop (C++20)
    for (std::vector<int> temp = {1, 2, 3}; auto n : temp) {
        std::cout << n << " ";
    }
}

// Custom range support
class Range {
    int start_, end_;

public:
    Range(int start, int end) : start_(start), end_(end) {}

    struct Iterator {
        int current;
        Iterator(int val) : current(val) {}
        int operator*() const { return current; }
        Iterator& operator++() { ++current; return *this; }
        bool operator!=(const Iterator& other) const {
            return current != other.current;
        }
    };

    Iterator begin() const { return Iterator(start_); }
    Iterator end() const { return Iterator(end_); }
};

void use_custom_range() {
    for (int i : Range(0, 10)) {
        std::cout << i << " ";
    }
}
```

## Uniform Initialization

Uniform initialization using braces provides consistent syntax and prevents
narrowing conversions.

```cpp
#include <vector>
#include <string>
#include <map>

struct Point {
    int x, y;
};

void uniform_initialization() {
    // Built-in types
    int a{42};
    double pi{3.14159};

    // Containers
    std::vector<int> numbers{1, 2, 3, 4, 5};
    std::map<std::string, int> ages{
        {"Alice", 30},
        {"Bob", 25}
    };

    // Aggregates
    Point p{10, 20};

    // Prevents narrowing
    // int x{3.14};  // Compiler error!
    int x = 3.14;    // Compiles (implicit conversion)

    // Empty initialization (zero/default)
    int zero{};      // 0
    std::string empty{};  // ""

    // Return value
    auto get_numbers = []() { return std::vector<int>{1, 2, 3}; };
}

// Most vexing parse solution
class Widget {
public:
    Widget() = default;
    Widget(int x) {}
};

void vexing_parse() {
    // Before C++11: declares a function!
    // Widget w();

    // Modern C++: creates an object
    Widget w{};     // Correct
    Widget w2{10};  // Also correct
}
```

## Move Semantics and Rvalue References

Move semantics enable efficient transfer of resources without copying,
crucial for performance.

```cpp
#include <vector>
#include <string>
#include <utility>
#include <iostream>

class Buffer {
    size_t size_;
    int* data_;

public:
    // Constructor
    Buffer(size_t size) : size_(size), data_(new int[size]) {
        std::cout << "Constructor\n";
    }

    // Copy constructor
    Buffer(const Buffer& other)
        : size_(other.size_), data_(new int[other.size_]) {
        std::copy(other.data_, other.data_ + size_, data_);
        std::cout << "Copy constructor\n";
    }

    // Move constructor
    Buffer(Buffer&& other) noexcept
        : size_(other.size_), data_(other.data_) {
        other.size_ = 0;
        other.data_ = nullptr;
        std::cout << "Move constructor\n";
    }

    // Copy assignment
    Buffer& operator=(const Buffer& other) {
        if (this != &other) {
            delete[] data_;
            size_ = other.size_;
            data_ = new int[size_];
            std::copy(other.data_, other.data_ + size_, data_);
            std::cout << "Copy assignment\n";
        }
        return *this;
    }

    // Move assignment
    Buffer& operator=(Buffer&& other) noexcept {
        if (this != &other) {
            delete[] data_;
            size_ = other.size_;
            data_ = other.data_;
            other.size_ = 0;
            other.data_ = nullptr;
            std::cout << "Move assignment\n";
        }
        return *this;
    }

    ~Buffer() { delete[] data_; }
};

void move_semantics_example() {
    Buffer b1(100);
    Buffer b2 = std::move(b1);  // Move, not copy

    std::vector<Buffer> buffers;
    buffers.push_back(Buffer(50));  // Move constructor used

    // Perfect forwarding
    auto make_buffer = [](auto&&... args) {
        return Buffer(std::forward<decltype(args)>(args)...);
    };
}
```

## Variadic Templates

Variadic templates enable functions and classes that accept any number of
arguments.

```cpp
#include <iostream>
#include <string>

// Base case
void print(

Related in General