C++: C++モダン機能

最終更新:2026-08-31

レッスン47では、テンプレートメタプログラミングについて学びました。

ここでは、C++のモダン機能について学びます。

C++11/17/20/23の新機能を使いこなすことは、現代C++開発者の必須スキルです。


1. C++進化の歴史

(1) 1.1 C++標準の変遷

バージョン 重要な新機能
C++11 2011 ラムダ、auto、スマートポインタ、constexpr
C++14 2014 汎用ラムダ、std::make_unique
C++17 2017 std::optionalstd::variant、畳み込み式
C++20 2020 コンセプト、Ranges、コルーチン
C++23 2023 std::expected、Deducing This

(2) 1.2 なぜモダンC++を学ぶ?

利点 説明
パフォーマンス ムーブセマンティクス、constexpr
安全性 スマートポインタ、std::optional
可読性 auto、ラムダ、Range-based for
生産性 std::format、構造化束縛



2. auto

(1) 2.1 基本的な使い方

▶ サンプル 1:autoの使用(難易度 ⭐)

CPP
#include <iostream>
#include <vector>

int main() {
    auto x = 42;           // int
    auto y = 3.14;         // double
    auto s = "hello";      // const char*
    auto v = std::vector<int>{1, 2, 3};
    
    for (auto& elem : v) {
        std::cout << elem << std::endl;
    }
    
    return 0;
}
▶ 試してみよう

(2) 2.2 autoの応用

用法 説明
auto 型推論
auto& 参照
const auto& const参照
auto&& ユニバーサル参照



3. ラムダ式

(1) 3.1 基本的な使い方

▶ サンプル:ラムダの使用(難易度 ⭐)

CPP
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    
    // ラムダで出力
    std::for_each(v.begin(), v.end(), [](int x) {
        std::cout << x << " ";
    });
    std::cout << std::endl;
    
    return 0;
}
▶ 試してみよう

(2) 3.2 キャプチャ

キャプチャ 説明
[=] すべての変数を値でキャプチャ
[&] すべての変数を参照でキャプチャ
[x] xを値でキャプチャ
[&x] xを参照でキャプチャ
[this] thisポインタをキャプチャ



4. std::optional

(1) 4.1 基本的な使い方

問題: 「値がない」状態をどう表現するか?

解決策: std::optional(C++17)

▶ サンプル:optionalの使用(難易度 ⭐⭐)

TEXT 📖 参照専用
#include <iostream>
#include <optional>

std::optional<int> findValue(const std::vector<int>& v, int target) {
    for (int x : v) {
        if (x == target) {
            return x;
        }
    }
    return std::nullopt; // 値なし
}

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    
    auto result = findValue(v, 3);
    if (result) {
        std::cout << "見つかりました:" << *result << std::endl;
    } else {
        std::cout << "見つかりません" << std::endl;
    }
    
    return 0;
}



5. std::variant

(1) 5.1 基本的な使い方

問題: 複数の型を格納できる変数が必要?

解決策: std::variant(C++17)——型安全なunion

▶ サンプル:variantの使用(難易度 ⭐⭐)

CPP
#include <iostream>
#include <variant>
#include <string>

int main() {
    std::variant<int, double, std::string> v;
    
    v = 42;
    std::cout << std::get<int>(v) << std::endl;
    
    v = 3.14;
    std::cout << std::get<double>(v) << std::endl;
    
    v = "hello";
    std::cout << std::get<std::string>(v) << std::endl;
    
    return 0;
}
▶ 試してみよう

(2) 5.2 std::visit

CPP
#include <iostream>
#include <variant>

struct Visitor {
    void operator()(int i) { std::cout << "int: " << i << std::endl; }
    void operator()(double d) { std::cout << "double: " << d << std::endl; }
    void operator()(const std::string& s) { std::cout << "string: " << s << std::endl; }
};

int main() {
    std::variant<int, double, std::string> v = "hello";
    std::visit(Visitor{}, v);
    
    return 0;
}



6. std::string_view

(1) 6.1 基本的な使い方

問題: 文字列をコピーせずに参照したい?

解決策: std::string_view(C++17)——文字列への軽量なビュー

▶ サンプル:string_viewの使用(難易度 ⭐)

CPP
#include <iostream>
#include <string>
#include <string_view>

void printString(std::string_view sv) {
    std::cout << sv << std::endl;
}

int main() {
    std::string s = "Hello, World!";
    printString(s);        // std::stringから
    printString("Hello");  // const char*から
    
    return 0;
}
▶ 試してみよう
💡 ヒント:

  • std::string_view はコピーしないため高速
  • ただし、元の文字列が有効である必要がある



7. コンセプト

(1) 7.1 基本的な使い方

問題: テンプレートパラメータに制約を設けたい?

解決策: コンセプト(C++20)

▶ サンプル:コンセプトの使用(難易度 ⭐⭐)

TEXT 📖 参照専用
#include <iostream>
#include <concepts>

// Numeric型のみ受け取る
template<typename T>
requires std::numeric_limits<T>::is_integer
void printNumber(T value) {
    std::cout << value << std::endl;
}

int main() {
    printNumber(42);     // OK
    printNumber(3.14);   // OK
    // printNumber("hello"); // エラー!
    
    return 0;
}

(2) 7.2 標準コンセプト

コンセプト 説明
std::integral 整数型
std::floating_point 浮動小数点型
std::same_as 同じ型
std::derived_from 派生関係
std::convertible_to 変換可能



8. 総合例

▶ サンプル 1:モダンC++の機能統合(難易度 ⭐⭐⭐)

CPP
#include <iostream>
#include <vector>
#include <algorithm>
#include <optional>
#include <string_view>

// モダンC++の機能を統合した関数
auto findInVector(const std::vector<int>& v, int target) -> std::optional<size_t> {
    auto it = std::find(v.begin(), v.end(), target);
    if (it != v.end()) {
        return std::distance(v.begin(), it);
    }
    return std::nullopt;
}

int main() {
    std::vector v = {1, 2, 3, 4, 5}; // CTAD(C++17)
    
    auto index = findInVector(v, 3);
    if (index) {
        std::cout << "インデックス:" << *index << std::endl;
    }
    
    return 0;
}
▶ 試してみよう

▶ サンプル 2:構造化束縛(難易度 ⭐⭐)

CPP
#include <iostream>
#include <map>
#include <string>

int main() {
    std::map<std::string, int> scores = {
        {"Alice", 90},
        {"Bob", 85}
    };

    // 構造化束縛でkeyとvalueを取り出す
    for (const auto& [name, score] : scores) {
        std::cout << name << ": " << score << std::endl;
    }

    return 0;
}
▶ 試してみよう

出力:

TEXT 📖 参照専用
Alice: 90
Bob: 85

▶ サンプル 3:std::optionalの実践(難易度 ⭐⭐)

CPP
#include <iostream>
#include <optional>
#include <string>

std::optional<std::string> findUser(int id) {
    if (id == 1) {
        return "Alice";
    } else if (id == 2) {
        return "Bob";
    }
    return std::nullopt;
}

int main() {
    auto user1 = findUser(1);
    auto user3 = findUser(3);

    if (user1) {
        std::cout << "ユーザー1: " << *user1 << std::endl;
    } else {
        std::cout << "ユーザー1が見つかりません" << std::endl;
    }

    std::cout << "ユーザー3: " << user3.value_or("不明") << std::endl;

    return 0;
}
▶ 試してみよう

出力:

TEXT 📖 参照専用
ユーザー1: Alice
ユーザー3: 不明

❓ よくある質問

Q:autoを使いすぎると可読性が下がる? A: はい。型が明確でない場合、明示的に書く方が良いです。


Q:std::optionalとポインタの使い分けは? A:std::optional は値がない状態を表現、ポインタはオブジェクトへの参照を表現。


Q:コンセプトは難しい? A:基本的な使い方は簡単。標準コンセプトを使うだけでも十分役立ちます。


📖 まとめ

トピック 要点
auto 型推論
ラムダ 無名関数、キャプチャ
std::optional 「値がない」状態を表現
std::variant 型安全なunion
std::string_view 文字列への軽量なビュー
コンセプト テンプレート制約

📝 練習問題

  1. 初級(難易度 ⭐): std::optional を使って、辞書(map)からキーを検索し、見つかったら値を返す関数を書く。

  2. 中級(難易度 ⭐⭐): std::variantstd::visit を使って、複数の型(int、double、string)を格納・処理する関数を書く。

  3. 上級(難易度 ⭐⭐⭐): C++20コンセプトを使って、「加算可能」な型のみを受け取る関数テンプレートを書く(requires 句を使用)。



次のレッスン:パフォーマンス最適化(#49)

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%