C++每三年會制定新的標準,截至2025年11月,最新的C++23正在各大編譯器中實作中。
而下一個標準的C++26也在標準化委員會中進行制定。
此次將介紹C++23新增的功能以及C++26中提議的功能,並附上程式碼範例,總結C++的最新動向。
※本文章基於公開的標準化文件和cppreference,從一般開發者的角度進行整理。
C++由ISO每三年週期更新。最新版本為C++23,下一個版本為C++26,但在實際開發現場,C++17和C++20仍然是主流。不同版本間可以使用的功能差異很大,因此了解哪些標準新增了什麼功能十分重要。

出典: ISO C++ Standards Committee
上圖顯示了從C++98到未來C++29的標準化流向。藍色條代表正式標準規範,綠色條則是以技術規範(TS)並行開發的功能群。
特別注意的點
【主要編譯器概要】
| 編譯器 | C++20 | C++23 | C++26(實驗性) |
|---|---|---|---|
| GCC 14.2 | ✅ 完全 | ✅ 幾乎實作完成 | -std=c++2c 可試用部分功能 |
| Clang 18 | ✅ 完全 | ✅ 主要功能已支援 | 僅試作靜態反射、模式匹配等部分功能 |
| MSVC 17.11 | ✅ 幾乎完全 | 🔶 語言和STL皆在支持中 | ❌ 無官方支援(擴展功能水平有限) |
※截至2025年11月的資訊。
※詳細的功能別支援狀況可參考 cppreference。
C++23雖然不是大規模的變更,但添加了許多日常生活中非常有用的功能。此處從易於使用的新增功能開始介紹。
std::expected - 錯誤處理革命實現了類似Rust風格的錯誤處理,不再需要使用例外。
#include <expected>
#include <string>
#include <iostream>
#include <fstream>
#include <filesystem>
// 讀取檔案的函數範例
std::expected<std::string, std::string> read_config(const std::string& path) {
if (path.empty()) {
return std::unexpected{"路徑為空"};
}
if (!std::filesystem::exists(path)) {
return std::unexpected{"檔案不存在: " + path};
}
// 實際的讀取處理
std::ifstream file(path);
if (!file) {
return std::unexpected{"無法打開檔案"};
}
std::string content((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
return content;
}
// 使用範例
int main() {
auto result = read_config("config.json");
if (result) {
std::println("設定內容: {}", *result);
} else {
std::println("錯誤: {}", result.error());
}
// 方法鏈的使用
auto processed = read_config("data.json")
.transform([](const std::string& s) { return s.size(); })
.value_or(0);
}
傳統函數需要拋出例外或以返回值方式傳遞錯誤碼。std::expected是一種表示“成功值或錯誤值”的類型,特別在禁止使用例外的嵌入式和遊戲開發中非常受用。
std::print / std::println - 型別安全的輸出終於可以告別printf了!
#include <print>
#include <vector>
#include <chrono>
#include <format>
struct Point {
double x, y;
};
// 自定義型別的格式化
template<>
struct std::formatter<Point> : std::formatter<std::string> {
auto format(const Point& p, format_context& ctx) const {
return std::formatter<std::string>::format(
std::format("({:.2f}, {:.2f})", p.x, p.y), ctx);
}
};
int main() {
// 基本用法
std::println("你好, {}!", "世界");
// 結合多種型別
std::println("整數: {}, 浮點數: {:.2f}, 字串: {}",
42, 3.14159, "test");
// 容器的輸出
std::vector<int> vec = {1, 2, 3, 4, 5};
std::println("向量: {}", vec);
// 自定義型別
Point p{3.14, 2.71};
std::println("座標: {}", p);
// 輸出時間
auto now = std::chrono::system_clock::now();
std::println("當前時間: {:%Y-%m-%d %H:%M:%S}", now);
}
新增了可直接格式化並輸出到標準輸出的函數。因為編譯時進行型別檢查,可以避免printf中格式字串與實際參數不匹配而導致的錯誤。
deducing this - 簡化方法鏈CRTP(Curiously Recurring Template Pattern)不再需要。
class Builder {
private:
std::string result_;
public:
// 傳統的方法(C++20之前)
// Builder& add_old(const std::string& s) & {
// result_ += s;
// return *this;
// }
// Builder&& add_old(const std::string& s) && {
// result_ += s;
// return std::move(*this);
// }
// C++23: 使用deducing this整合為一個函數
template<class Self>
auto&& add(this Self&& self, const std::string& s) {
self.result_ += s;
return std::forward<Self>(self);
}
std::string build() const { return result_; }
};
// 使用範例
auto result = Builder{}
.add("你好")
.add(" ")
.add("世界")
.build(); // "你好 世界"
在類的成員函數中,可以透過模板取得this的型別。這樣會使得返還成員函數鏈的程式碼變得更加簡單。
std::mdspan - 多維陣列視圖支持在科學計算和遊戲開發中經常使用的矩陣運算。
#include <mdspan>
#include <vector>
void process_matrix() {
// 將一維陣列視為二維
std::vector<float> data(100 * 200);
// 解析為100x200的矩陣
std::mdspan<float, std::extents<size_t, 100, 200>> matrix(data.data());
// 二維訪問
for (size_t i = 0; i < matrix.extent(0); ++i) {
for (size_t j = 0; j < matrix.extent(1); ++j) {
matrix(i, j) = i * j; // C++23的多維下標
}
}
// 動態大小的情況
std::mdspan<float, std::dextents<size_t, 2>> dynamic_matrix(
data.data(), 100, 200);
}
新增了便於進行科學計算和遊戲開發的多維陣列訪問。能夠將一維陣列作為多維陣列使用,從而實現針對內存佈局的高效處理。
C++26正在研究一系列旨在使現有C++更加現代化和自動化的方式。尤其受到矚目的是將大幅簡化元編程的功能群。
※注意:本章中介紹的C++26功能仍在提議和審議中,規範、語法和名稱可能會在未來的WG21會議中變更。
從代碼中獲取型別信息,並能以元方式處理程序結構的功能。這將使JSON序列化的自動生成、enum到字串的轉換以及大量模板代碼的自動化成為可能。
// C++26提案(語法可能會變更)
template<typename T>
void serialize_to_json(const T& obj) {
std::print("{{");
bool first = true;
for (...) {
if (!first) std::print(", ");
first = false;
std::print("\"{}\": ", member.name());
serialize_value(obj.*member.pointer());
}
std::print("}}");
}
struct Person {
std::string name;
int age;
double height;
};
// 自動轉為JSON
Person p{"Alice", 30, 165.5};
serialize_to_json(p); // {"name": "Alice", "age": 30, "height": 165.5}
擴展switch語句,能包含結構體的解構與條件語句的描述。函數式語言中常見的功能最終也導入到C++。
// C++26提案
std::variant<int, double, std::string> value = 42;
inspect(value) {
<int> i => std::println("整數: {}", i);
<double> d if (d > 0) => std::println("正數: {}", d);
<std::string> s => std::println("字串: {}", s);
_ => std::println("其它");
}
// 與結構化綁定的結合
struct Point { int x, y; };
std::optional<Point> maybe_point = Point{10, 20};
inspect(maybe_point) {
<std::nullopt> => std::println("無");
<Point{.x = 0, .y = 0}> => std::println("原點");
<Point{.x = x, .y = y}> if (x == y) => std::println("對角線: {}", x);
<Point{.x = x, .y = y}> => std::println("點: ({}, {})", x, y);
}
std::embed - 編譯時資源嵌入將資源檔案(圖片、HTML等)嵌入到源代碼中的功能。無需在編譯後隨附檔案,使配發更加簡單。
// C++26提案
#include <embed>
// 嵌入著色器代碼
constexpr std::span<const std::byte> shader =
std::embed("shaders/vertex.glsl");
// 嵌入HTML模板
constexpr std::string_view html_template =
std::embed_string("templates/index.html");
// 嵌入二進制數據
constexpr auto icon_data = std::embed("assets/icon.png");
在系統編程領域,許多強調內存安全性的 Rust 和 Google為了C++代碼庫的遷移而開發的 Carbon 等新選擇正逐漸出現。
但實際上,眾多既有的C++資產和新語言間的共存正在逐漸形成。
Rust擁有獨特的設計理念,而Carbon則明確提供C++的遷移路徑,這是二者的不同點。
// C++側的接口
extern "C" {
// Rust可調用的函數
void process_data(const uint8_t* data, size_t len);
}
// 呼叫Rust側的高速處理
extern "C" {
void rust_parallel_compute(float* array, size_t size);
}
class HybridProcessor {
std::vector<float> data_;
public:
void compute() {
// 現存的C++代碼
prepare_data();
// 性能關鍵部分由Rust處理
rust_parallel_compute(data_.data(), data_.size());
// 結果的後處理在C++中進行
postprocess();
}
};
| 專案類型 | 推薦方法 |
|---|---|
| 新建Web服務 | 優先考慮Rust |
| 現有遊戲引擎 | 繼續使用C++ + 部分使用Rust |
| 嵌入式系統 | C++(重視實時性) |
| 系統工具 | 考慮Go/Rust |
要使用C++23的功能,只需在編譯器和CMake中指定標準版本即可。
先前需要使用 -fcoroutines 等實驗性標誌,但自 C++20以後不再需要。
<details><summary>查看範例</summary>
cmake_minimum_required(VERSION 3.25)
project(ModernCppExample LANGUAGES CXX)
# ---- 明確指定C++23(禁用擴展)----
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# ---- 稍微提高警告級別(防止現場事故)----
if(MSVC)
add_compile_options(/W4 /permissive-)
else()
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# ---- (可選)需在Clang + 非Apple Unix中使用libc++ ----
option(USE_LIBCXX "在非Apple Unix中使用Clang的libc++" OFF)
if(USE_LIBCXX AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT APPLE AND NOT WIN32)
add_compile_options(-stdlib=libc++)
add_link_options(-stdlib=libc++)
endif()
# ---- (可選)使用C++26預覽特性(提議階段,規範變更風險)----
option(EXPERIMENTAL_CPP26 "啟用C++26預覽特性" OFF)
if(EXPERIMENTAL_CPP26)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
# GCC/Clang用預覽功能,添加 -std=c++2c
add_compile_options(-std=c++2c)
add_compile_definitions(CPP26_PREVIEW)
elseif(MSVC)
# MSVC對C++26的預覽支援尚不完善,須小心
message(WARNING "MSVC的C++26預覽支援尚不完善,/std:c++latest下可部分測試,請自擔風險。")
# add_compile_options(/std:c++latest) # ←如需使用,請自行決定開啟
add_compile_definitions(CPP26_PREVIEW)
endif()
endif()
# ---- 生成執行檔(樣本)----
# 請在現有專案中用自己的目標替換
add_executable(app
src/main.cpp
)
# ---- 參考備註(舊標誌已不再需要/不推薦)----
# -fcoroutines / -fcoroutines-ts : 自C++20以後不再需要(已標準化)
# -fmodules-ts : 用於Modules TS。目前的導入應考慮各個編譯器的方案及
# CMake的 FILE_SET(cxx_modules)(不要輕易添加TS標誌)
# -stdlib=libc++ : 僅在Clang + 某些Unix中使用libc++的情況(由上方選項控制)
</details>
C++是 謹慎且穩步發展的基礎技術。此次總結了C++的最新動向。
重點
- C++23已進入實用階段,可以使用
std::expected和std::print等功能。- C++26計劃引入反射與模式匹配等革新功能。
- Rust和Carbon與其「取代」的關係,更是「共存與補充」。
- 結合大量既有的C++資產與新功能,使現代開發成為可能。
※本文章資訊截至2025年11月整理而成。
原文出處:https://qiita.com/Sakai_path/items/24537a84c2437e9e527f