Chapter 3: A Quick Overview of C++20_《C++20Get the details》_notes

发布于:2025-04-03 ⋅ 阅读:(59) ⋅ 点赞:(0)


A Quick Overview of C++20

1. Concepts
Key Concepts:

  • Definition: Constraints on template parameters to enforce semantic requirements.
  • Advantages: Better error messages, improved template code readability, and direct expression of intent.
  • Syntax: concept, requires, and abbreviated function templates.

Code Example:

#include <type_traits>

template<typename T>
concept Integral = std::is_integral_v<T>;

Integral auto gcd(Integral auto a, Integral auto b) {
    return (b == 0) ? a : gcd(b, a % b);
}

int main() {
    // Valid usage
    static_assert(gcd(12, 18) == 6);

    // Compilation error (non-integral type)
    // gcd(12.5, 18.7);
    return 0;
}

Explanation:

  • Integral concept enforces that types must be integral (e.g., int, long).
  • The gcd function uses abbreviated syntax (Integral auto) to constrain parameters.
  • Test Output: Compiles successfully for integers; uncommenting the gcd(12.5, 18.7) line produces a clear error message.

2. Modules
Key Concepts:

  • Purpose: Replace header files with modular code to improve compilation speed and encapsulation.
  • Syntax: export module, import, and export.

Code Example:

// math.cppm (module interface)
export module math;
export int add(int a, int b) { return a + b; }

// main.cpp
import math;
#include <iostream>

int main() {
    std::cout << add(2000, 20) << '\n'; // Output: 2020
    return 0;
}

Compilation:

  • Use C++20-compatible compiler flags (e.g., g++ -std=c++20 -fmodules-ts).
  • Test Output: Prints 2020.

3. Ranges Library
Key Concepts:

  • Lazy Evaluation: Operations are deferred until iteration.
  • Composability: Use | to chain range adaptors (e.g., filter, transform).

Code Example:

#include <vector>
#include <ranges>
#include <iostream>

int main() {
    std::vector<int> nums{1, 2, 3, 4, 5};
    auto even_square = nums 
        | std::views::filter([](int n) { return n % 2 == 0; })
        | std::views::transform([](int n) { return n * n; });

    for (int n : even_square) {
        std::cout << n << ' '; // Output: 4 16
    }
    return 0;
}

Explanation:

  • filter removes odd numbers; transform squares remaining elements.
  • Test Output: 4 16.

4. Coroutines
Key Concepts:

  • Cooperative Multitasking: Suspend/resume execution with co_yield, co_await.
  • Generator Pattern: Produce sequences lazily.

Code Example:

#include <coroutine>
#include <iostream>

template<typename T>
struct Generator {
    struct promise_type {
        T value;
        auto yield_value(T val) {
            value = val;
            return std::suspend_always{};
        }
        auto initial_suspend() { return std::suspend_always{}; }
        auto final_suspend() noexcept { return std::suspend_always{}; }
        Generator get_return_object() { return Generator{this}; }
        void unhandled_exception() {}
    };

    using Handle = std::coroutine_handle<promise_type>;
    Handle coro;

    explicit Generator(promise_type* p) : coro(Handle::from_promise(*p)) {}
    ~Generator() { if (coro) coro.destroy(); }

    T next() {
        coro.resume();
        return coro.promise().value;
    }
};

Generator<int> range(int start, int end) {
    for (int i = start; i <= end; ++i) {
        co_yield i;
    }
}

int main() {
    auto gen = range(5, 10);
    while (true) {
        int val = gen.next();
        if (!gen.coro.done()) {
            std::cout << val << ' '; // Output: 5 6 7 8 9 10
        } else {
            break;
        }
    }
    return 0;
}

Explanation:

  • Generator<T> manages coroutine state.
  • co_yield suspends execution and emits a value.
  • Test Output: 5 6 7 8 9 10.

5. Three-Way Comparison (<=>)
Key Concepts:

  • Spaceship Operator: Simplifies defining comparison operators.
  • Compiler-Generated: Auto-generates ==, !=, <, >, <=, >=.

Code Example:

#include <compare>

struct Point {
    int x, y;
    auto operator<=>(const Point&) const = default;
};

int main() {
    Point p1{1, 2}, p2{3, 4};
    std::cout << (p1 < p2) << '\n'; // Output: 1 (true)
    return 0;
}

Explanation:

  • operator<=> defaults all comparison operators.
  • Test Output: 1.

6. Designated Initialization
Key Concepts:

  • Aggregate Initialization: Initialize struct members by name.
  • Order-Sensitive: Members must be declared in order.

Code Example:

struct Vec3 {
    int x, y, z;
};

int main() {
    Vec3 v{.x = 1, .y = 2, .z = 3}; // Valid
    // Vec3 v{.z = 3, .y = 2, .x = 1}; // Error: wrong order
    return 0;
}

Test Output: Compiles successfully for valid initialization; reordering fields causes an error.


7. consteval and constinit
Key Concepts:

  • consteval: Enforces compile-time evaluation (immediate functions).
  • constinit: Ensures static initialization.

Code Example:

consteval int square(int n) { return n * n; }

constinit static int x = square(5); // Valid

int main() {
    constexpr int y = square(4); // Valid
    // int z = square(rand()); // Error: not constexpr
    return 0;
}

Explanation:

  • square must be evaluated at compile time.
  • Test Output: Compiles if valid; uncommenting invalid lines produces errors.

Summary

  • Concepts enforce type constraints, improving template code.
  • Modules replace headers for faster compilation.
  • Ranges enable composable, lazy algorithms.
  • Coroutines simplify asynchronous code and generators.
  • Three-Way Comparison reduces boilerplate.
  • Designated Initialization clarifies struct initialization.
  • consteval/constinit control evaluation timing.

All examples are compilable with C++20-compliant compilers (e.g., GCC 11+, Clang 12+). Use flags like -std=c++20 and -fmodules-ts where required.

Multiple-Choice Questions

1. Which statements about C++20 Concepts are correct?
A) Concepts can be used to constrain auto in function parameters.
B) A concept must always be defined using the requires keyword.
C) The std::integral concept is part of the C++20 standard library.
D) Abbreviated function templates using concepts automatically deduce template parameters.

2. What are valid characteristics of C++20 Modules?
A) Modules eliminate the need for header files.
B) export module math; exports all declarations in the module.
C) import statements can only appear at global scope.
D) Modules guarantee faster compilation than traditional headers.

3. Which statements about Ranges views are true?
A) Views always own their elements.
B) std::views::filter can be composed with std::views::transform using |.
C) Range adaptors perform eager evaluation by default.
D) views::common ensures a range can be used with legacy C++ algorithms.

4. What are correct behaviors of coroutines?
A) co_yield suspends execution and returns a value.
B) co_await must be used in every coroutine.
C) Coroutine state is allocated on the heap by default.
D) A coroutine must return void.

5. Which features are part of C++20’s core language?
A) Three-way comparison operator (<=>)
B) Designated initializers for aggregate types
C) consteval functions
D) Atomic smart pointers

6. What is true about designated initialization?
A) It allows initializing non-aggregate types.
B) Members must be initialized in declaration order.
C) Supports initializing base class members.
D) Can skip members with default values.

7. Which statements about consteval/constinit are correct?
A) consteval functions can be called at runtime.
B) constinit ensures constant initialization.
C) constexpr variables can use constinit.
D) consteval implies constexpr.

8. What are valid C++20 template improvements?
A) Non-type template parameters can be floating-point.
B) Template lambda parameters.
C) Conditionally explicit constructors using requires.
D) Partial specialization of concepts.

9. Which attributes are introduced in C++20?
A) [[nodiscard]] with message
B) [[likely]]
C) [[deprecated]]
D) [[no_unique_address]]

10. What are true about std::span?
A) Owns the underlying data.
B) Can represent a runtime-sized range.
C) Guaranteed to be non-const.
D) Supports static extents.


Design Problems

1. Concept-Constrained Generic Algorithm
Design a generic sum algorithm using concepts that:

  • Works only with arithmetic types
  • Accepts a container via ranges
  • Returns the sum as a common type of elements

2. Module-Based Math Library
Create a module geo that:

  • Exports a Point struct with x/y coordinates
  • Exports functions distance() and midpoint()
  • Uses internal implementation details hidden from consumers

3. Lazy Ranges Pipeline
Implement a program that:

  • Generates infinite Fibonacci sequence
  • Filters even numbers
  • Transforms to string representation
  • Takes first 10 elements using ranges views

4. Coroutine-Based Generator
Create a Generator<T> template supporting:

  • co_yield for producing values
  • Proper promise_type handling
  • Iteration via standard range-based for loops

5. Atomic Smart Pointer Usage
Implement a thread-safe queue using:

  • std::atomic<std::shared_ptr> for lock-free push/pop
  • Hazard pointers for safe memory reclamation
  • Demonstrate usage with producer/consumer threads

Answers & Explanations

Multiple-Choice Answers

  1. A, C, D

    • B: Concepts can be defined with bool expressions.
    • C: std::integral is predefined.
    • D: Auto concepts deduce template parameters.
  2. A, D

    • B: Only explicitly exported items are visible.
    • C: Imports can appear in namespace scope.
    • D: Modules reduce redundant compilation.
  3. B, D

    • A: Views are non-owning.
    • C: Views are lazy by default.
  4. A, C

    • B: co_return is optional.
    • D: Coroutines can return various types.
  5. A, B, C

    • D: Atomic smart pointers are library features.
  6. B, D

    • A: Only aggregates.
    • C: Only direct members.
  7. B, D

    • A: consteval is immediate.
    • C: constinit applies to variables.
  8. A, B, C

    • D: Concepts can’t be specialized.
  9. A, B, D

    • C: [[deprecated]] predates C++20.
  10. B, D

    • A: span is non-owning.
    • C: Can be const-qualified.

Design Problem Solutions

1. Concept-Constrained Generic Algorithm

#include <concepts>
#include <ranges>
#include <vector>

template<std::ranges::range R>
requires std::integral<std::ranges::range_value_t<R>>
auto sum(R&& range) {
    using T = std::ranges::range_value_t<R>;
    T total{};
    for (auto&& elem : range) {
        total += elem;
    }
    return total;
}

int main() {
    std::vector<int> v{1, 2, 3};
    static_assert(sum(v) == 6); // Test
}

2. Module-Based Math Library

// geo.ixx
export module geo;

export struct Point {
    double x, y;
};

export double distance(Point a, Point b);
export Point midpoint(Point a, Point b);

// geo.cpp
module geo;

double distance(Point a, Point b) {
    return std::hypot(a.x-b.x, a.y-b.y);
}

Point midpoint(Point a, Point b) {
    return {(a.x + b.x)/2, (a.y + b.y)/2};
}

3. Lazy Ranges Pipeline

#include <ranges>
#include <iostream>
#include <string>

auto fibs = std::views::iota(0) 
    | std::views::transform([](int n) {
        int a=0, b=1;
        while(n-- >0) std::tie(a,b) = std::pair(b, a+b);
        return a;
    });

int main() {
    for (auto s : fibs | std::views::filter([](int x){return x%2==0;})
                       | std::views::transform([](int x){return std::to_string(x);})
                       | std::views::take(10)) {
        std::cout << s << ' ';
    }
}

4. Coroutine-Based Generator

#include <coroutine>
#include <iostream>

template<typename T>
struct Generator {
    struct promise_type {
        T value_;
        auto yield_value(T val) {
            value_ = val;
            return std::suspend_always{};
        }
        auto initial_suspend() { return std::suspend_always{}; }
        auto final_suspend() noexcept { return std::suspend_always{}; }
        void return_void() {}
        Generator get_return_object() { return Generator{Handle::from_promise(*this)}; }
        void unhandled_exception() { std::terminate(); }
    };
    
    using Handle = std::coroutine_handle<promise_type>;
    Handle handle_;
    
    explicit Generator(Handle h) : handle_(h) {}
    ~Generator() { if (handle_) handle_.destroy(); }
    
    T value() const { return handle_.promise().value_; }
    bool next() {
        if (!handle_.done()) handle_.resume();
        return !handle_.done();
    }
    
    struct iterator {
        Generator& g;
        bool operator!=(std::nullptr_t) const { return !g.handle_.done(); }
        void operator++() { g.next(); }
        T operator*() const { return g.value(); }
    };
    
    iterator begin() { return {*this}; }
    std::nullptr_t end() { return nullptr; }
};

Generator<int> range(int from, int to) {
    for (int i=from; i<to; ++i)
        co_yield i;
}

int main() {
    for (int i : range(5, 10)) {
        std::cout << i << ' '; // Outputs 5 6 7 8 9
    }
}

5. Atomic Smart Pointer Queue

#include <atomic>
#include <memory>
#include <thread>

template<typename T>
class LockFreeQueue {
    struct Node {
        T data;
        std::shared_ptr<Node> next;
    };
    std::atomic<std::shared_ptr<Node>> head;
    
public:
    void push(T value) {
        auto new_node = std::make_shared<Node>();
        new_node->data = value;
        new_node->next = head.load(std::memory_order_relaxed);
        while (!head.compare_exchange_weak(new_node->next, new_node,
               std::memory_order_release, std::memory_order_relaxed));
    }
    
    std::shared_ptr<T> pop() {
        std::shared_ptr<Node> old_head = head.load(std::memory_order_relaxed);
        while (old_head && !head.compare_exchange_weak(old_head, old_head->next,
               std::memory_order_acquire, std::memory_order_relaxed));
        return old_head ? std::make_shared<T>(old_head->data) : nullptr;
    }
};

int main() {
    LockFreeQueue<int> q;
    std::thread producer([&]{
        for (int i=0; i<10; ++i) q.push(i);
    });
    std::thread consumer([&]{
        for (int i=0; i<10; ++i) {
            while (!q.pop()); // Spin
        }
    });
    producer.join();
    consumer.join();
}

Each solution includes testable code that compiles with C++20 flags (-std=c++20 for GCC/Clang, /std:c++latest for MSVC). The designs demonstrate proper usage of C++20 features while addressing complex scenarios.


网站公告

今日签到

点亮在社区的每一天
去签到