C++20是C++历史上仅次于C++11的重大版本,其设计理念标志着语言的根本性转变:
- 约束编程:通过Concepts将类型要求显式化
- 异步原生化:Coroutines将异步编程提升到语言层面
- 模块化架构:Modules彻底改革代码组织方式
- 函数式增强:Ranges引入惰性求值和组合式编程
- 编译期强化:进一步扩展编译期计算能力
// C++17的SFINAE噩梦
template<typename T>
std::enable_if_t<
std::is_arithmetic_v<T> &&
!std::is_same_v<T, bool> &&
std::is_copy_constructible_v<T>,
T
>
complex_math_operation(T value) {
return value * value + 1;
}
// C++20的优雅表达
template<std::integral T>
requires (!std::same_as<T, bool>)
T complex_math_operation(T value) {
return value * value + 1;
}// 基础概念定义
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
// 复合概念
template<typename T>
concept Container = requires(T container) {
typename T::value_type; // 嵌套类型要求
typename T::iterator;
container.begin(); // 表达式要求
container.end();
{ container.size() } -> std::convertible_to<size_t>; // 类型要求
container.empty(); // 简单表达式要求
};
// 高级概念组合
template<typename T>
concept SortableContainer = Container<T> && requires(T container) {
std::sort(container.begin(), container.end());
};template<typename T>
concept ComplexConcept = requires(T obj) {
// 1. 简单要求:表达式必须有效
obj.method();
// 2. 类型要求:类型必须存在
typename T::value_type;
typename T::iterator;
// 3. 复合要求:表达式有效且满足类型约束
{ obj.size() } -> std::convertible_to<size_t>;
{ obj.at(0) } -> std::same_as<typename T::value_type&>;
// 4. 嵌套要求:满足其他概念
requires std::default_initializable<T>;
requires Numeric<typename T::value_type>;
};// 概念特化的函数重载
template<typename T>
void process(T value) {
std::cout << "Generic processing\n";
}
template<std::integral T>
void process(T value) {
std::cout << "Integer processing: " << value * 2 << '\n';
}
template<std::floating_point T>
void process(T value) {
std::cout << "Float processing: " << value / 2.0 << '\n';
}
// 概念的部分特化
template<typename T>
class Storage {
std::vector<T> data;
};
template<std::integral T>
class Storage<T> {
std::vector<T> data;
size_t bit_count = sizeof(T) * 8; // 整数特化的额外功能
};template<typename T>
concept SafeNumeric = requires {
// 短路求值:如果T不是算术类型,后续检查不会进行
requires std::is_arithmetic_v<T>;
requires !std::is_same_v<T, bool>;
requires std::is_copy_constructible_v<T>;
};#include <ranges>
std::vector<int> numbers{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 传统STL的多步操作
std::vector<int> temp;
std::copy_if(numbers.begin(), numbers.end(), std::back_inserter(temp),
[](int n) { return n % 2 == 0; });
std::vector<int> result;
std::transform(temp.begin(), temp.end(), std::back_inserter(result),
[](int n) { return n * n; });
// C++20 Ranges的组合式操作(惰性求值)
auto result_range = numbers
| std::views::filter([](int n) { return n % 2 == 0; })
| std::views::transform([](int n) { return n * n; })
| std::views::take(3); // 只取前3个元素
// 此时还没有实际计算,只有在遍历时才计算
for (int value : result_range) {
std::cout << value << " "; // 现在才开始计算
}// 自定义一个斐波那契数列视图
class fibonacci_view : public std::ranges::view_interface<fibonacci_view> {
size_t count_;
public:
explicit fibonacci_view(size_t count) : count_(count) {}
class iterator {
size_t pos_, a_, b_;
public:
using value_type = size_t;
using difference_type = std::ptrdiff_t;
iterator(size_t pos = 0) : pos_(pos), a_(0), b_(1) {}
size_t operator*() const { return a_; }
iterator& operator++() {
auto temp = a_ + b_;
a_ = b_;
b_ = temp;
++pos_;
return *this;
}
bool operator==(const iterator& other) const {
return pos_ == other.pos_;
}
};
iterator begin() const { return iterator(0); }
iterator end() const { return iterator(count_); }
};
// 使用自定义视图
auto fib_range = fibonacci_view(10)
| std::views::filter([](size_t n) { return n % 2 == 0; });// 传统算法需要多次遍历
std::vector<std::string> words{"hello", "world", "cpp", "twenty"};
auto count = std::count_if(words.begin(), words.end(),
[](const auto& s) { return s.length() > 3; });
// Ranges算法的优化版本
auto count_optimized = std::ranges::count_if(words,
[](const auto& s) { return s.length() > 3; });
// 投影(Projection)的强大功能
struct Person {
std::string name;
int age;
};
std::vector<Person> people{{"Alice", 30}, {"Bob", 25}, {"Carol", 35}};
// 直接基于成员排序,无需lambda
std::ranges::sort(people, {}, &Person::age); // 按年龄排序
// 组合投影
auto adult_names = people
| std::views::filter([](const Person& p) { return p.age >= 18; })
| std::views::transform(&Person::name);constexpr auto compute_at_compile_time() {
std::array data{1, 2, 3, 4, 5};
// 编译期范围操作
auto result = data
| std::views::transform([](int x) { return x * x; })
| std::views::filter([](int x) { return x > 10; });
// 编译期聚合
int sum = 0;
for (int value : result) {
sum += value;
}
return sum;
}
constexpr int compile_time_result = compute_at_compile_time();#include <coroutine>
// generator协程
std::generator<int> fibonacci() {
int a = 0, b = 1;
while (true) {
co_yield a; // 暂停并返回值
auto temp = a;
a = b;
b = temp + b;
}
}
// task协程
std::task<int> async_computation(int x) {
// 模拟异步操作
co_await std::this_thread::sleep_for(std::chrono::milliseconds(100));
co_return x * x; // 返回值并结束协程
}
// 使用协程
auto fib_gen = fibonacci();
for (int i = 0; i < 10; ++i) {
std::cout << fib_gen() << " "; // 获取下一个值
}// 协程的promise_type定义了协程行为
template<typename T>
struct task {
struct promise_type {
T value_;
std::exception_ptr exception_;
task get_return_object() {
return task{std::coroutine_handle<promise_type>::from_promise(*this)};
}
std::suspend_never initial_suspend() { return {}; } // 立即开始
std::suspend_always final_suspend() noexcept { return {}; } // 暂停在结尾
void return_value(T value) { value_ = std::move(value); }
void unhandled_exception() { exception_ = std::current_exception(); }
};
std::coroutine_handle<promise_type> coro_;
explicit task(std::coroutine_handle<promise_type> coro) : coro_(coro) {}
~task() {
if (coro_) coro_.destroy();
}
T get_result() {
if (!coro_.done()) {
coro_.resume(); // 恢复协程执行
}
if (coro_.promise().exception_) {
std::rethrow_exception(coro_.promise().exception_);
}
return std::move(coro_.promise().value_);
}
};struct timer_awaitable {
std::chrono::milliseconds duration_;
explicit timer_awaitable(std::chrono::milliseconds duration)
: duration_(duration) {}
bool await_ready() const { return false; } // 总是需要等待
void await_suspend(std::coroutine_handle<> coro) {
// 在其他线程中设置定时器
std::thread([coro, this]() {
std::this_thread::sleep_for(duration_);
coro.resume(); // 时间到后恢复协程
}).detach();
}
void await_resume() {} // 恢复时无返回值
};
// 便利函数
timer_awaitable delay(std::chrono::milliseconds ms) {
return timer_awaitable{ms};
}
// 使用自定义awaitable
std::task<void> timed_operation() {
std::cout << "Starting operation...\n";
co_await delay(std::chrono::milliseconds(1000));
std::cout << "Operation completed after delay\n";
}// 异步文件读取协程
std::task<std::string> async_read_file(const std::string& filename) {
// 异步打开文件
auto file_handle = co_await async_open(filename);
// 异步读取内容
auto content = co_await async_read_all(file_handle);
// 异步关闭文件
co_await async_close(file_handle);
co_return content;
}
// 协程组合
std::task<void> process_files(const std::vector<std::string>& filenames) {
std::vector<std::task<std::string>> tasks;
// 启动所有异步读取任务
for (const auto& filename : filenames) {
tasks.push_back(async_read_file(filename));
}
// 等待所有任务完成
for (auto& task : tasks) {
auto content = co_await task;
process_content(content);
}
}// 传统头文件的问题
// math_utils.h
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
#include <vector>
#include <algorithm>
#include <numeric>
class MathUtils {
public:
static double average(const std::vector<double>& values);
static double standard_deviation(const std::vector<double>& values);
};
#endif
// C++20模块的解决方案
// math_utils.cppm (模块接口文件)
export module math_utils;
import <vector>;
import <algorithm>;
import <numeric>;
export class MathUtils {
public:
static double average(const std::vector<double>& values);
static double standard_deviation(const std::vector<double>& values);
};// math_utils.cpp (模块实现文件)
module math_utils;
import <cmath>;
double MathUtils::average(const std::vector<double>& values) {
if (values.empty()) return 0.0;
return std::accumulate(values.begin(), values.end(), 0.0) / values.size();
}
double MathUtils::standard_deviation(const std::vector<double>& values) {
double avg = average(values);
double variance = 0.0;
for (double value : values) {
variance += (value - avg) * (value - avg);
}
return std::sqrt(variance / values.size());
}// advanced_math.cppm
export module advanced_math;
// 内部辅助函数,不导出
namespace internal {
double helper_function(double x) {
return x * x + 1;
}
}
// 只导出公共接口
export namespace advanced_math {
double complex_calculation(double x, double y) {
return internal::helper_function(x) + internal::helper_function(y);
}
// 导出特定函数
export double public_utility(double value);
}
// 不导出的私有实现
double private_calculation(double x) {
return x * 2; // 模块外部无法访问
}// graphics.cppm (主模块)
export module graphics;
export import :shapes; // 导入并重新导出shapes分区
export import :colors; // 导入并重新导出colors分区
import :internal_utils; // 仅导入,不重新导出
// graphics-shapes.cppm (shapes分区)
export module graphics:shapes;
export class Circle {
double radius_;
public:
explicit Circle(double r) : radius_(r) {}
double area() const;
};
// graphics-colors.cppm (colors分区)
export module graphics:colors;
export enum class Color { Red, Green, Blue };
export Color mix_colors(Color a, Color b);
// graphics-internal.cppm (内部分区)
module graphics:internal_utils;
// 内部实用函数,不导出到模块外部
double pi() { return 3.14159265359; }// constexpr可以在运行时执行
constexpr int factorial_constexpr(int n) {
return n <= 1 ? 1 : n * factorial_constexpr(n - 1);
}
// consteval强制在编译期执行
consteval int factorial_consteval(int n) {
return n <= 1 ? 1 : n * factorial_consteval(n - 1);
}
void example() {
constexpr int compile_time = 5;
int runtime = 5;
auto a = factorial_constexpr(compile_time); // 编译期执行
auto b = factorial_constexpr(runtime); // 运行时执行
auto c = factorial_consteval(compile_time); // 编译期执行
// auto d = factorial_consteval(runtime); // 编译错误!
}consteval bool is_power_of_two(size_t value) {
return value > 0 && (value & (value - 1)) == 0;
}
template<size_t BufferSize>
class FixedBuffer {
static_assert(is_power_of_two(BufferSize),
"Buffer size must be power of two");
std::array<char, BufferSize> buffer_;
public:
// ...
};
// 编译期字符串处理
consteval size_t string_length(const char* str) {
const char* end = str;
while (*end) ++end;
return end - str;
}
template<size_t N>
consteval auto make_string_literal(const char (&str)[N]) {
return str;
}// 传统方式可能存在初始化顺序问题
int expensive_computation() {
// 复杂计算
return 42;
}
// 可能在main之前或之后初始化
static int global_value = expensive_computation();
// C++20保证编译期初始化
constinit static int safe_global = 42; // 保证在编译期初始化
// 也可以与consteval结合
consteval int compute_config() {
return 100;
}
constinit static int config_value = compute_config();#include <compare>
struct Point {
int x, y;
// 自动生成所有六个比较运算符
auto operator<=>(const Point& other) const = default;
bool operator==(const Point& other) const = default;
};
// 现在可以使用所有比较运算符
Point p1{1, 2};
Point p2{3, 4};
bool equal = (p1 == p2); // false
bool not_equal = (p1 != p2); // true
bool less = (p1 < p2); // true
auto ordering = (p1 <=> p2); // std::strong_ordering::lessstruct Person {
std::string name;
int age;
// 自定义比较:先按年龄,再按姓名
std::strong_ordering operator<=>(const Person& other) const {
if (auto cmp = age <=> other.age; cmp != 0) {
return cmp;
}
return name <=> other.name;
}
bool operator==(const Person& other) const {
return name == other.name && age == other.age;
}
};
// 三种比较类别
class WeakComparable {
public:
std::weak_ordering operator<=>(const WeakComparable& other) const {
// 弱排序:等价但不相等的情况
return std::weak_ordering::equivalent;
}
};
class PartialComparable {
public:
std::partial_ordering operator<=>(const PartialComparable& other) const {
// 偏序:可能无法比较(如NaN)
return std::partial_ordering::unordered;
}
};// C++20支持模板参数
auto generic_lambda = []<typename T>(T value) {
if constexpr (std::is_arithmetic_v<T>) {
return value * 2;
} else {
return value;
}
};
auto result1 = generic_lambda(42); // int
auto result2 = generic_lambda(3.14); // double
auto result3 = generic_lambda("hello"); // const char*template<typename... Args>
auto make_lambda(Args... args) {
// 捕获参数包
return [args...](){
return (args + ...); // 折叠表达式
};
}
auto sum_lambda = make_lambda(1, 2, 3, 4, 5);
int result = sum_lambda(); // 15auto compile_time_lambda = []() consteval {
return 42;
};
constexpr int value = compile_time_lambda(); // 编译期执行struct Config {
std::string host = "localhost";
int port = 8080;
bool ssl_enabled = false;
int timeout_ms = 5000;
};
// 指定初始化器,提高可读性
Config config{
.host = "example.com",
.port = 443,
.ssl_enabled = true
// timeout_ms使用默认值
};#include <format>
std::string name = "Alice";
int age = 30;
double salary = 75000.50;
// 类型安全的格式化
std::string message = std::format(
"Employee: {}, Age: {}, Salary: {:.2f}",
name, age, salary
);
// 命名参数
std::string formatted = std::format(
"Hello {name}, you are {age} years old",
std::make_format_args(name, age)
);#include <span>
void process_data(std::span<const int> data) {
// 统一处理数组、vector、array等
for (int value : data) {
std::cout << value << " ";
}
}
int arr[] = {1, 2, 3, 4, 5};
std::vector<int> vec{6, 7, 8, 9, 10};
std::array<int, 3> arr_obj{11, 12, 13};
process_data(arr); // C数组
process_data(vec); // vector
process_data(arr_obj); // array
process_data(std::span<int>{arr, 3}); // 子范围#include <thread>
#include <stop_token>
void background_task(std::stop_token stop_token) {
while (!stop_token.stop_requested()) {
// 执行工作
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
void example() {
std::jthread worker(background_task);
// 自动join,支持协作式取消
std::this_thread::sleep_for(std::chrono::seconds(1));
worker.request_stop(); // 请求停止
// worker析构时自动join
}C++20体现了C++语言设计的四个重要转向:
- Concepts让模板约束显式化
- Modules让依赖关系显式化
- consteval让编译期执行强制化
- Ranges引入惰性求值和组合式编程
- 协程支持声明式异步编程
- 折叠表达式简化函数式操作
- consteval/constinit扩展编译期计算
- Concepts在编译期进行类型检查
- 模板lambda增强编译期代码生成
- 三向比较简化比较运算符定义
- Designated initializers提高初始化的可读性
- std::format提供类型安全的格式化
C++20不仅仅是语言特性的增加,而是编程范式的演进,为C++在现代软件开发中保持竞争力奠定了坚实基础。这些特性的组合使用将彻底改变C++代码的编写方式,让C++在保持性能优势的同时,获得了现代编程语言的表达力和安全性。