はじめに
C++は3年ごとに新しい規格が策定されていて、2025年11月時点では最新のC++23が各コンパイラで実装されつつあります。
そして、次期規格のC++26も標準化委員会で策定が進んでいます。
今回は、C++23で追加された機能とC++26で提案されている機能をコード例とともに紹介し、C++の最新動向をまとめました。
※本記事は公開されている標準化ドキュメントやcppreferenceを基に、一般の開発者視点でまとめたものです。
1. C++標準の進化タイムライン
ISOによって3年周期で更新されるC++。最新はC++23、次期はC++26ですが、実際の開発現場ではC++17やC++20がまだ主流です。バージョンによって使える機能は大きく異なるため、どの規格で何が追加されたかを把握しておくことが重要です。
現在のC++エコシステム
出典: ISO C++ Standards Committee
上図は、C++98から将来のC++29までの標準化の流れを示しています。青いバーが正式な標準規格、緑のバーがTechnical Specifications(TS)として並行開発されている機能群です。
特筆すべき点
3年周期での規格更新(C++11以降)
大規模機能はTSとして別枠で開発後、本体に統合
Modules、Coroutines、RangesなどがTSから標準へ移行した実例
コンパイラサポート状況
【主要コンパイラ概要】
- GCC - GNU Compiler Collection、Linux/Unix系の標準
- Clang - LLVM系、macOS標準、優れたエラーメッセージ
- MSVC - Microsoft Visual C++、Windows/Visual Studio標準
| コンパイラ | C++20 | C++23 | C++26(実験的) |
|---|---|---|---|
| GCC 14.2 | ✅ 完全 | ✅ ほぼ実装済 |
-std=c++2c で一部機能を試験的に利用可能 |
| Clang 18 | ✅ 完全 | ✅ 主要機能は対応済 | 静的リフレクション・パターンマッチなど一部のみ試験実装 |
| MSVC 17.11 | ✅ ほぼ完全 | 🔶 言語・STLとも対応中 | ❌ 公式サポートなし(拡張機能レベルも限定的) |
※2025年11月時点の情報です。
※詳細な機能別サポート状況は cppreference で確認してください。
2. C++23の実用的な新機能
C++23は大規模な変更ではないものの、日常的に役立つ便利な機能が多く追加されました。ここでは現場で使いやすいものから紹介します。
2.1 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はRustのResultのような「成功値 or エラー値」を表す型です。例外禁止の組込み・ゲームでは特に重宝されます。
2.2 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("Hello, {}!", "World");
// 複数の型を混在
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のようなフォーマット文字列と実引数の不一致によるバグを防げます。
2.3 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 で1つの関数に統合
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("Hello")
.add(" ")
.add("World")
.build(); // "Hello World"
クラスのメンバ関数に対して、thisの型をテンプレートで取得できます。これにより、メンバ関数チェーンを返すコードなどが書きやすくなります。
2.4 std::mdspan - 多次元配列ビュー
科学計算やゲーム開発で頻繁に使用される行列演算をサポート。
#include <mdspan>
#include <vector>
void process_matrix() {
// 1次元配列を2次元として扱う
std::vector<float> data(100 * 200);
// 100x200の行列として解釈
std::mdspan<float, std::extents<size_t, 100, 200>> matrix(data.data());
// 2次元アクセス
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のmultidimensional subscript
}
}
// 動的サイズの場合
std::mdspan<float, std::dextents<size_t, 2>> dynamic_matrix(
data.data(), 100, 200);
}
科学計算やゲーム開発で便利な多次元配列アクセスが標準ライブラリに追加されました。1次元配列を多次元配列として扱えるため、メモリレイアウトを意識した高速な処理が可能です。
3. C++26の革新的機能(プレビュー)
C++26では、既存のC++をより近代化・自動化するための仕組みが検討されています。特に注目されているのは、メタプログラミングを大幅に簡素化する機能群です。
※注意:本章で紹介するC++26の機能は、まだ提案・審議中の内容です。仕様・構文・名称は今後のWG21会議で変更される可能性があります。
3.1 静的リフレクション - メタプログラミングの新時代
コードから型情報を取得し、プログラムの構造をメタ的に扱える機能です。これによりJSONシリアライズの自動生成、enumから文字列への変換、大量のテンプレートコードの自動化が可能になります。
// C++26提案(構文は変更される可能性あり)
template<typename T>
void serialize_to_json(const T& obj) {
std::print("{{");
bool first = true;
for... (constexpr auto member : ^T::members()) {
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}
3.2 パターンマッチング - より表現力豊かな分岐
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);
}
3.3 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");
4. C++とRust/Carbonの共存戦略
システムプログラミング分野では、メモリ安全性を重視した 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検討 |
5. 実践的なC++23/26導入ガイド
C++23の機能を使うには、コンパイラとCMakeで標準バージョンを指定するだけで問題ありません。
以前は -fcoroutines などの試験的フラグが必要でしたが、C++20以降では不要です。
サンプルを見る
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 "Use libc++ with Clang on non-Apple Unix" 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 "Enable C++26 preview features" 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++ を使う場合のみ(上のオプションで制御)
まとめ
C++は 慎重かつ着実に進化を続ける現役の基盤技術です。今回は進化するC++の最新動向をまとめてみました。
ポイント
- C++23は実用段階に入り、
std::expectedやstd::printなどが使える- C++26ではリフレクション・パターンマッチなど革新的機能が予定
- Rust/Carbonとは「置き換え」ではなく「共存・補完」の関係
- 既存の膨大なC++資産と新機能を組み合わせることで、モダンな開発が可能
※この記事の情報は2025年11月にまとめたものになります。
