はじめに
C++20はC++11以来の大型アップデート。Concepts、Ranges、Coroutinesなど革新的な機能が追加された。
特にConceptsは「テンプレートのエラーメッセージが読めない」というC++の古来の問題を解決してくれる。
1. Concepts(コンセプト)
テンプレートの制約を明確に:
#include <concepts>
// 数値型を制約
template<typename T>
concept Numeric = is_arithmetic_v<T>;
template<Numeric T>
T add(T a, T b) {
return a + b;
}
add(3, 4); // OK
add(1.5, 2.5); // OK
// add("a", "b"); // エラー!
// カスタムコンセプト
template<typename T>
concept Printable = requires(T t) {
{ cout << t } -> same_as<ostream&>;
};
2. Ranges
コンテナ操作をパイプラインで:
#include <ranges>
vector<int> nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// フィルタ→変換をパイプで連結
auto result = nums
| views::filter([](int n) { return n % 2 == 0; })
| views::transform([](int n) { return n * n; });
// {4, 16, 36, 64, 100}
// take / drop
auto first3 = nums | views::take(3); // {1, 2, 3}
auto skip3 = nums | views::drop(3); // {4, 5, ...}
// reverse
auto rev = nums | views::reverse;
// iota(連続整数生成)
for (int n : views::iota(1, 6)) { // 1, 2, 3, 4, 5
cout << n << endl;
}
3. 三方比較演算子 (<=>)
「宇宙船演算子」で比較を一括定義:
struct Point {
int x, y;
auto operator<=>(const Point&) const = default;
};
Point p1{1, 2}, p2{1, 3};
p1 == p2; // false
p1 < p2; // true
p1 != p2; // true
// ==, !=, <, <=, >, >= すべて自動生成
4. std::format
Pythonライクな文字列フォーマット:
#include <format>
string name = "World";
format("Hello, {}!", name); // "Hello, World!"
format("Pi = {:.2f}", 3.14159); // "Pi = 3.14"
format("{:>10}", "right"); // " right"
format("{:^10}", "center"); // " center "
format("Hex: {:x}", 255); // "Hex: ff"
format("Bin: {:b}", 255); // "Bin: 11111111"
5. std::span
配列の軽量ビュー:
#include <span>
void process(span<const int> s) {
for (int n : s) { /* ... */ }
}
int arr[] = {1, 2, 3, 4, 5};
vector<int> vec = {1, 2, 3};
process(arr); // 配列
process(vec); // vector
// どちらも同じ関数で処理可能
// 部分取得
span<int> sp(arr);
sp.subspan(1, 3); // {2, 3, 4}
6. constexpr の拡張
vectorやstringもconstexprで使用可能:
constexpr int sum() {
vector<int> v = {1, 2, 3, 4, 5};
int total = 0;
for (int n : v) total += n;
return total;
}
constexpr int result = sum(); // 15(コンパイル時)
7. consteval / constinit
// consteval: 必ずコンパイル時評価
consteval int square(int n) {
return n * n;
}
constexpr int x = square(5); // OK
// int y = square(runtime_val); // エラー!
// constinit: 静的初期化を強制
constinit int global = 42;
8. 指示付き初期化
C99スタイルの初期化:
struct Config {
int width = 800;
int height = 600;
bool fullscreen = false;
};
Config cfg = {
.width = 1920,
.height = 1080,
.fullscreen = true
};
9. ラムダの拡張
// テンプレートラムダ
auto print = []<typename T>(vector<T> const& vec) {
for (const auto& v : vec) cout << v;
};
// thisのコピーキャプチャ
struct S {
int value;
auto get_lambda() {
return [*this]() { return value; };
}
};
10. std::source_location
ファイル名・行番号を自動取得:
#include <source_location>
void log(string_view msg,
source_location loc = source_location::current()) {
cout << loc.file_name() << ":" << loc.line()
<< " " << msg << endl;
}
log("Error!"); // main.cpp:42 Error!
11. std::numbers
数学定数:
#include <numbers>
numbers::pi; // 3.14159...
numbers::e; // 2.71828...
numbers::sqrt2; // 1.41421...
numbers::phi; // 1.61803... (黄金比)
numbers::ln2; // 0.69314...
12. std::bit
ビット操作:
#include <bit>
popcount(0b00101100u); // 3 (1のビット数)
has_single_bit(64u); // true (2の累乗)
bit_ceil(44u); // 64 (以上の最小2累乗)
bit_floor(44u); // 32 (以下の最大2累乗)
countl_zero(0b00101100u); // 26 (左側のゼロ)
countr_zero(0b00101100u); // 2 (右側のゼロ)
13. using enum
enum値を直接使用:
enum class Color { Red, Green, Blue };
void func() {
using enum Color;
Color c = Red; // Color::Red の代わり
}
14. contains
map/setの存在確認が簡単に:
set<int> s = {1, 2, 3};
map<string, int> m = {{"one", 1}};
s.contains(2); // true
m.contains("one"); // true
// count() や find() より直感的
15. starts_with / ends_with
文字列の前方/後方一致:
string s = "Hello World";
s.starts_with("Hello"); // true
s.ends_with("World"); // true
まとめ
| 機能 | 説明 |
|---|---|
| Concepts | テンプレート制約 |
| Ranges | パイプラインコンテナ操作 |
<=> |
三方比較(宇宙船演算子) |
format |
文字列フォーマット |
span |
配列ビュー |
consteval |
コンパイル時専用関数 |
| 指示付き初期化 | .member = value |
source_location |
ログ用ファイル/行情報 |
numbers |
数学定数 |
bit |
ビット操作 |
contains |
存在確認 |
starts_with |
前方一致 |