cpp-modern-features

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Modern C++ Features

现代C++特性

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.
现代C++(C++11及后续版本)带来了重大改进,让C++代码更具表达力、更安全且更易用。本技能涵盖了核心的现代特性,包括类型推导、lambda表达式、范围for循环、智能初始化以及C++20的最新新增特性。

Auto Type Inference

auto类型推导

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";
    }
}
auto
关键字支持自动类型推导,在保持类型安全的同时减少代码冗余。
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

Lambda表达式

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; };
}
Lambda表达式提供了内联匿名函数,是现代C++算法和回调函数的核心工具。
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

范围for循环

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 << " ";
    }
}
范围for循环提供了简洁、安全的容器和范围迭代方式。
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
}
使用大括号的统一初始化提供了一致的语法,同时可以防止窄化转换。
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)...);
    };
}
移动语义支持无需复制即可高效转移资源,对性能提升至关重要。
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() {
    std::cout << "\n";
}

// Recursive variadic template
template<typename T, typename... Args>
void print(T first, Args... rest) {
    std::cout << first << " ";
    print(rest...);
}

// Fold expressions (C++17)
template<typename... Args>
auto sum(Args... args) {
    return (args + ...);
}

template<typename... Args>
auto sum_with_init(Args... args) {
    return (args + ... + 0);
}

// Perfect forwarding with variadic templates
template<typename T, typename... Args>
std::unique_ptr<T> make_unique_custom(Args&&... args) {
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

void variadic_examples() {
    print(1, 2.5, "hello", std::string("world"));

    auto total = sum(1, 2, 3, 4, 5);  // 15

    // Fold expressions for various operations
    auto all_true = [](auto... args) {
        return (args && ...);
    };

    auto any_true = [](auto... args) {
        return (args || ...);
    };
}
可变参数模板支持接受任意数量参数的函数和类。
cpp
#include <iostream>
#include <string>

// Base case
void print() {
    std::cout << "\n";
}

// Recursive variadic template
template<typename T, typename... Args>
void print(T first, Args... rest) {
    std::cout << first << " ";
    print(rest...);
}

// Fold expressions (C++17)
template<typename... Args>
auto sum(Args... args) {
    return (args + ...);
}

template<typename... Args>
auto sum_with_init(Args... args) {
    return (args + ... + 0);
}

// Perfect forwarding with variadic templates
template<typename T, typename... Args>
std::unique_ptr<T> make_unique_custom(Args&&... args) {
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

void variadic_examples() {
    print(1, 2.5, "hello", std::string("world"));

    auto total = sum(1, 2, 3, 4, 5);  // 15

    // Fold expressions for various operations
    auto all_true = [](auto... args) {
        return (args && ...);
    };

    auto any_true = [](auto... args) {
        return (args || ...);
    };
}

Structured Bindings (C++17)

结构化绑定(C++17)

Structured bindings decompose objects into their constituent parts, improving code readability.
cpp
#include <tuple>
#include <map>
#include <string>
#include <array>

struct Person {
    std::string name;
    int age;
    double salary;
};

std::tuple<int, std::string, double> get_employee() {
    return {42, "Alice", 75000.0};
}

void structured_bindings() {
    // Tuple decomposition
    auto [id, name, salary] = get_employee();

    // Pair decomposition
    std::pair<int, std::string> p{1, "one"};
    auto [num, text] = p;

    // Struct decomposition
    Person person{"Bob", 30, 80000.0};
    auto [pname, page, psalary] = person;

    // Array decomposition
    std::array<int, 3> arr{1, 2, 3};
    auto [a, b, c] = arr;

    // Map iteration
    std::map<std::string, int> scores{{"Alice", 95}, {"Bob", 87}};
    for (const auto& [name, score] : scores) {
        std::cout << name << ": " << score << "\n";
    }

    // References
    auto& [rname, rage, rsalary] = person;
    rage = 31;  // Modifies person.age
}
结构化绑定可以将对象分解为其组成部分,提升代码可读性。
cpp
#include <tuple>
#include <map>
#include <string>
#include <array>

struct Person {
    std::string name;
    int age;
    double salary;
};

std::tuple<int, std::string, double> get_employee() {
    return {42, "Alice", 75000.0};
}

void structured_bindings() {
    // Tuple decomposition
    auto [id, name, salary] = get_employee();

    // Pair decomposition
    std::pair<int, std::string> p{1, "one"};
    auto [num, text] = p;

    // Struct decomposition
    Person person{"Bob", 30, 80000.0};
    auto [pname, page, psalary] = person;

    // Array decomposition
    std::array<int, 3> arr{1, 2, 3};
    auto [a, b, c] = arr;

    // Map iteration
    std::map<std::string, int> scores{{"Alice", 95}, {"Bob", 87}};
    for (const auto& [name, score] : scores) {
        std::cout << name << ": " << score << "\n";
    }

    // References
    auto& [rname, rage, rsalary] = person;
    rage = 31;  // Modifies person.age
}

Concepts (C++20)

Concepts(C++20)

Concepts constrain template parameters, providing better error messages and clearer interfaces.
cpp
#include <concepts>
#include <iostream>
#include <vector>

// Define custom concept
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;

// Use concept to constrain template
template<Numeric T>
T add(T a, T b) {
    return a + b;
}

// Concept with multiple constraints
template<typename T>
concept Printable = requires(T t) {
    { std::cout << t } -> std::convertible_to<std::ostream&>;
};

template<Printable T>
void print(const T& value) {
    std::cout << value << "\n";
}

// Range concept
template<typename T>
concept Range = requires(T r) {
    r.begin();
    r.end();
};

template<Range R>
void print_range(const R& range) {
    for (const auto& item : range) {
        std::cout << item << " ";
    }
    std::cout << "\n";
}

// Concept with associated types
template<typename T>
concept Container = requires(T c) {
    typename T::value_type;
    typename T::iterator;
    { c.begin() } -> std::same_as<typename T::iterator>;
    { c.end() } -> std::same_as<typename T::iterator>;
    { c.size() } -> std::convertible_to<std::size_t>;
};

template<Container C>
void process_container(const C& container) {
    std::cout << "Size: " << container.size() << "\n";
}

void concepts_example() {
    auto result = add(5, 10);      // OK
    auto dresult = add(5.5, 2.3);  // OK
    // auto sresult = add("hi", "there");  // Error: doesn't satisfy
                                             // Numeric

    print(42);
    print("Hello");

    std::vector<int> vec{1, 2, 3};
    print_range(vec);
    process_container(vec);
}
Concepts可以约束模板参数,提供更清晰的错误提示和更明确的接口。
cpp
#include <concepts>
#include <iostream>
#include <vector>

// Define custom concept
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;

// Use concept to constrain template
template<Numeric T>
T add(T a, T b) {
    return a + b;
}

// Concept with multiple constraints
template<typename T>
concept Printable = requires(T t) {
    { std::cout << t } -> std::convertible_to<std::ostream&>;
};

template<Printable T>
void print(const T& value) {
    std::cout << value << "\n";
}

// Range concept
template<typename T>
concept Range = requires(T r) {
    r.begin();
    r.end();
};

template<Range R>
void print_range(const R& range) {
    for (const auto& item : range) {
        std::cout << item << " ";
    }
    std::cout << "\n";
}

// Concept with associated types
template<typename T>
concept Container = requires(T c) {
    typename T::value_type;
    typename T::iterator;
    { c.begin() } -> std::same_as<typename T::iterator>;
    { c.end() } -> std::same_as<typename T::iterator>;
    { c.size() } -> std::convertible_to<std::size_t>;
};

template<Container C>
void process_container(const C& container) {
    std::cout << "Size: " << container.size() << "\n";
}

void concepts_example() {
    auto result = add(5, 10);      // OK
    auto dresult = add(5.5, 2.3);  // OK
    // auto sresult = add("hi", "there");  // Error: doesn't satisfy
                                             // Numeric

    print(42);
    print("Hello");

    std::vector<int> vec{1, 2, 3};
    print_range(vec);
    process_container(vec);
}

Ranges Library (C++20)

Ranges库(C++20)

The ranges library provides composable algorithms and views for working with sequences.
cpp
#include <ranges>
#include <vector>
#include <iostream>
#include <algorithm>

void ranges_examples() {
    std::vector<int> numbers{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    // Views are lazy and composable
    auto even = [](int n) { return n % 2 == 0; };
    auto square = [](int n) { return n * n; };

    // Compose operations without intermediate containers
    auto result = numbers
        | std::views::filter(even)
        | std::views::transform(square)
        | std::views::take(3);

    for (int n : result) {
        std::cout << n << " ";  // 4 16 36
    }
    std::cout << "\n";

    // Range algorithms
    std::ranges::sort(numbers, std::greater{});

    // Find with projection
    struct Person {
        std::string name;
        int age;
    };

    std::vector<Person> people{
        {"Alice", 30},
        {"Bob", 25},
        {"Charlie", 35}
    };

    auto it = std::ranges::find(people, "Bob", &Person::name);

    // Views::iota for number generation
    for (int i : std::views::iota(1, 6)) {
        std::cout << i << " ";  // 1 2 3 4 5
    }
    std::cout << "\n";

    // Split view
    std::string text = "one,two,three";
    for (auto word : text | std::views::split(',')) {
        for (char c : word) {
            std::cout << c;
        }
        std::cout << " ";
    }
}
Ranges库提供了可组合的算法和视图,用于处理序列数据。
cpp
#include <ranges>
#include <vector>
#include <iostream>
#include <algorithm>

void ranges_examples() {
    std::vector<int> numbers{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    // Views are lazy and composable
    auto even = [](int n) { return n % 2 == 0; };
    auto square = [](int n) { return n * n; };

    // Compose operations without intermediate containers
    auto result = numbers
        | std::views::filter(even)
        | std::views::transform(square)
        | std::views::take(3);

    for (int n : result) {
        std::cout << n << " ";  // 4 16 36
    }
    std::cout << "\n";

    // Range algorithms
    std::ranges::sort(numbers, std::greater{});

    // Find with projection
    struct Person {
        std::string name;
        int age;
    };

    std::vector<Person> people{
        {"Alice", 30},
        {"Bob", 25},
        {"Charlie", 35}
    };

    auto it = std::ranges::find(people, "Bob", &Person::name);

    // Views::iota for number generation
    for (int i : std::views::iota(1, 6)) {
        std::cout << i << " ";  // 1 2 3 4 5
    }
    std::cout << "\n";

    // Split view
    std::string text = "one,two,three";
    for (auto word : text | std::views::split(',')) {
        for (char c : word) {
            std::cout << c;
        }
        std::cout << " ";
    }
}

Best Practices

最佳实践

  1. Use
    auto
    for complex types and iterators but keep simple types explicit
  2. Prefer lambdas over function objects for inline operations and callbacks
  3. Use range-based for loops instead of manual iterator manipulation
  4. Initialize variables with
    {}
    to prevent narrowing conversions
  5. Implement move constructors and assignments for resource-owning classes
  6. Use
    std::move
    when transferring ownership, not for general optimization
  7. Prefer structured bindings over
    std::get<>()
    for tuples and pairs
  8. Use concepts to constrain templates and improve error messages
  9. Leverage ranges for composable, lazy operations on sequences
  10. Use
    const auto&
    for range-based loops with large objects
  1. 复杂类型和迭代器使用
    auto
    ,但简单类型建议显式声明
  2. 内联操作和回调函数优先使用lambda表达式而非函数对象
  3. 使用范围for循环替代手动迭代器操作
  4. 使用
    {}
    初始化变量以防止窄化转换
  5. 为资源持有类实现移动构造函数和移动赋值运算符
  6. 转移所有权时使用
    std::move
    ,不要将其用于通用优化
  7. 元组和pair优先使用结构化绑定而非
    std::get<>()
  8. 使用Concepts约束模板并改进错误提示
  9. 利用Ranges库实现可组合的惰性序列操作
  10. 处理大对象的范围for循环使用
    const auto&

Common Pitfalls

常见陷阱

  1. Overusing
    auto
    making code less readable when types provide clarity
  2. Capturing by reference in lambdas that outlive their captures
  3. Using
    std::move
    on const objects, which disables move semantics
  4. Forgetting
    noexcept
    on move operations, preventing optimizations
  5. Modifying containers while iterating with range-based for loops
  6. Dangling references from structured bindings of temporary objects
  7. Using fold expressions without considering operator precedence
  8. Assuming ranges views create copies instead of providing lazy views
  9. Moving from objects that will be used again later
  10. Not marking move constructors and assignments as
    noexcept
  1. 过度使用
    auto
    导致类型清晰性下降,降低代码可读性
  2. Lambda表达式中使用引用捕获,但捕获对象的生命周期短于Lambda
  3. 对const对象使用
    std::move
    ,这会禁用移动语义
  4. 移动操作未标记
    noexcept
    ,导致无法触发优化
  5. 使用范围for循环迭代时修改容器
  6. 对临时对象使用结构化绑定导致悬垂引用
  7. 使用折叠表达式时未考虑运算符优先级
  8. 误认为Ranges视图会创建副本,实际是惰性视图
  9. 移动对象后继续使用该对象
  10. 未将移动构造函数和移动赋值运算符标记为
    noexcept

When to Use Modern C++ Features

何时使用现代C++特性

Use modern C++ features when you need:
  • Cleaner, more expressive code with less boilerplate
  • Better type safety with concepts and structured bindings
  • Improved performance through move semantics
  • Functional programming patterns with lambdas and ranges
  • Generic programming with less template complexity
  • Safer resource management with smart pointers
  • Code that's easier to maintain and refactor
  • Better compiler error messages with concepts
  • Lazy evaluation and composition with ranges
  • Migration from older C++ codebases to modern standards
在以下场景中使用现代C++特性:
  • 需要更简洁、更具表达力且更少样板代码的实现
  • 需要通过Concepts和结构化绑定提升类型安全性
  • 需要通过移动语义提升性能
  • 需要使用Lambda表达式和Ranges实现函数式编程模式
  • 需要简化泛型编程的模板复杂度
  • 需要更安全的资源管理(如智能指针)
  • 需要更易于维护和重构的代码
  • 需要通过Concepts获得更清晰的编译器错误提示
  • 需要通过Ranges实现惰性求值和操作组合
  • 需要从旧版C++代码库迁移到现代标准

Resources

参考资源